问题
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 usedelete[]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-newa 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