Tech Off Thread

4 posts

Crash in std::vector (MSVC 2010 and MSVC 2012)

Back to Forum: Tech Off
  • User profile image
    oyefremov

    Hello, J have read nice article by Andrew Koenig Copying Container Elements From The C++ Library: It's Trickier Than It Looks. Article describe situations when user write code like this:

    v.push_back(v[0]);

    After it I decided to check how Microsoft's std::vector implementation handle push_back(..). Implementation use tricky pointer math to detect similar cases and handle it with separate code block. Than I recall similar method emplace_back that can not relay on argument's addresses so it can not use similar trick. And actually it did not. It just ignore problem at all and fails on following sample:

    #include <string>
    #include <vector>
    
    struct holder {
        holder(std::string d) 
            :data(std::move(d)) {}
        std::string data;
    };
    
    void main() {
        std::vector<holder> v;
        v.emplace_back("sample data");
        v.emplace_back(v[0].data);
    }

     

  • User profile image
    oyefremov

    Suggested implementation of emplace_back (for VS 2010 with one argument)

        template<class _Valty>
            void emplace_back(_Valty&& _Val)
            {    // insert element at end
                if (this->_Mylast == this->_Myend)
                {
                    size_type _Size = this->size();
                    if (max_size() - 1 < _Size)
                        _Xlen();
                    size_type _New_capacity = _Grow_to(_Size + 1);
    
                    _Myt _New_vector(this->_Alval);
                    _New_vector.reserve(_New_capacity);
    
                    _Cons_val(_New_vector._Alval, 
                        _New_vector._Myfirst + _Size,
                        _STD forward<_Valty>(_Val));
    
                    _TRY_BEGIN
                        // note, _Umove does not use allocator so it can not use _Cons_val (bug?)
                    _Umove(
                        this->_Myfirst, 
                        this->_Mylast, 
                        _New_vector._Myfirst);
                    _CATCH_ALL
                    _Dest_val(
                        _New_vector._Alval, 
                        _New_vector._Myfirst + _Size);
                    _RERAISE;
                    _CATCH_END
    
                    _New_vector._Mylast += _Size + 1;
                    std::swap(*this, _New_vector);
                    // _Orphan_range(this->_Mylast, this->_Mylast); Do we need it here???
                }
                else
                {
                    _Orphan_range(this->_Mylast, this->_Mylast);
                    _Cons_val(this->_Alval,
                        this->_Mylast,
                        _STD forward<_Valty>(_Val));
                    ++this->_Mylast;
                }
            }
    

  • User profile image
    STL

    This is a known bug, currently assigned to me.  We didn't have time to fix it in VS 2013.  It'll require careful surgery to the STL's most important container, so we want to take the time to do it right.

    By the way, you should upgrade from 2010 to 2012.  We added a bunch of features and fixed a bunch of bugs.

  • User profile image
    eddwo

    Kinda cool that STL is in charge of fixing bugs in the STL implementation.

    Another example of Nominative Determinism?

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.