I've got some training example of selt-made vector, it's not template for simplicity:
class UglyStringsVector {
public:
UglyStringsVector() = default;
explicit UglyStringsVector(size_t size);
UglyStringsVector(const UglyStringsVector&);
~UglyStringsVector();
std::string &operator[](size_t index);
std::string *begin();
std::string *end();
const std::string *begin() const;
const std::string *end() const;
size_t Size() const;
size_t Capacity() const;
void PushBack(std::string value);
void operator=(const UglyStringsVector &other);
private:
std::string *data = nullptr;
size_t size = 0;
size_t capacity = 0;
void ExpandIfNeeded();
};
Assignment operator is not implemented correctly:
UglyStringsVector& UglyStringsVector::operator=(const UglyStringsVector &other) {
delete[] data;
data = new std::string[other.capacity];
size = other.size;
capacity = other.capacity;
copy(other.begin(), other.end(), begin());
return *this;
}
As we see here, when this == &other
(I don't check this condition on purpose of question), it deletes its own memory (of course this is wrong), and then reallocates new strings on the same place (data = new std::string[other.capacity];
), strings are not uninitialized, because default constructor was called during operator new[]
, and then copy strings to themselves (copy(other.begin(), other.end(), begin());
).
Lets imagine than losing memory is not problem :-) Something whispers to me that copying memory to itself is undefined behavior, but I'm not sure. The question: is there any undefined behavior?
Assuming that data
is a valid pointer or nullptr
, then actually there's no UB at all.
With new std::string[other.capacity]
you create an "array" of default-initialized std::string
objects. A default-initialized (default-constructed basically) std::string
is a valid but empty string.
You then copy this array of empty strings to itself, which is fine.
Regarding the self-copying, it's similar to
int a = 0;
a = a;
which is weird but fine.