Is it nessary to destroy a string before constructing it again?

北战南征 提交于 2019-12-24 14:21:10

问题


As an exercise, I'm trying to write a class like a std::vector without using a template. The only type it holds is std::string.

Below is the strvec.h file:

class StrVec
{
public:
    //! Big 3
    StrVec():
        element(nullptr), first_free(nullptr), cap(nullptr)
    {}
    StrVec(const StrVec& s);
    StrVec&
    operator =(const StrVec& rhs);
    ~StrVec();

    //! public members
    void push_back(const std::string &s);

    std::size_t size() const        { return first_free - element; }
    std::size_t capacity() const    { return cap - element; }

    std::string* begin() const      { return element; }
    std::string* end() const        { return first_free; }


    void reserve(std::size_t n);
    void resize(std::size_t n);
  //^^^^^^^^^^^^^^^^^^^^^^^^^^^

private:

    //! data members
    std::string* element;       //  pointer to the first element
    std::string* first_free;    //  pointer to the first free element
    std::string* cap;           //  pointer to one past the end

    std::allocator<std::string> alloc;

    //! utilities 
    void reallocate();
    void chk_n_alloc()      { if (size() == capacity()) reallocate(); }
    void free();

    void wy_alloc_n_move(std::size_t n);

    std::pair<std::string*, std::string*>
    alloc_n_copy (std::string* b, std::string* e);
};

The three string*, element, first_free, and cap can be thought of as:

[0][1][2][3][unconstructed elements]
^           ^                       ^
element     first_free              cap

When implementing the member resize(size_t n), I have a problem. Say, v.resize(3) is called. As a result the pointer first_free must be moved forward one place and point to [3]. Something like:

[0][1][2][3][unconstructed elements]
^        ^                          ^
element  first_free                 cap

My question is how should I deal with [3]? Leave it there untouched? Or destroy it like:

if(n < size())
{
    for(auto p = element + n; p != first_free; /* empty */)
        alloc.destroy(p++);
    first_free = element + n;
}

Is the code alloc.destroy( somePointer) necessary here?


回答1:


Yes, definitely, you should call destroy on elements that are removed from the vector when resize() is called with an argument smaller than the current size of the vector. That's what std::vector does, too.

Note that destroy only calls the destructor on those elements; it does not deallocate any space (which would be wrong).

Since you are dealing with std::string, you probably think you could do without destruction if you are sure that you re-initialize the same std::string object later with a new value. But firstly, you can't be sure that a new string will be stored in the same place later, and secondly, for the new string a new object would be created (using placement-new, not copy-assignment), leaking the memory of the previous string (whose destructor would never have been called).




回答2:


What you should do depends on how you've initialised element, as you need your code to be consistent.

  • if you use new std::string[n] to create the array of strings, then they will all be pre-initialised, and when you necessarily use delete[] to deallocate them later their destructors will all be run. For that reason, you must not call the destructors manually in the intervening time unless you are certain you'll placement-new a valid object there again.

  • if you use something like static_cast<std::string*>(new char[sizeof(std::string) * n]) to create a buffer of un-initialised memory, then you must take full responsibility for calling the constructor and destructor of every element at appropriate times

With the first option, you wouldn't need to do anything for resize(3), but could call .clear() on the string to potentially free up some memory if you wanted.

With the second option, you must trigger the destructor for [3] (unless you're keeping some other record of which element eventually need destruction, which seems a clumsy model).

The issues are identical to just having memory for a single string that is "in use" at different times during the program. Do you spend the time to construct it before first use then assign to it, or do you leave it uninitialised then copy-construct it with placement new? Do you clear it when unused or destruct it? Either model can work with careful implementation. The first approach tends to be easier to implement correctly, the second model slightly more efficient when the array capacity is much greater than the number of element that end up being used.



来源:https://stackoverflow.com/questions/20930063/is-it-nessary-to-destroy-a-string-before-constructing-it-again

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!