0

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?

ValFF
  • 3
  • 1
  • See e.g. https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom – Bob__ Mar 04 '20 at 07:36
  • @Bob__ thanks for the answer, but I know about copy-and-swap and know that my code is incorrect at all )) The question is about undefined behavior in synthetic example... – ValFF Mar 04 '20 at 07:40
  • See [The rule of three/five/zero](https://en.cppreference.com/w/cpp/language/rule_of_three) for tips on the copy/assignment. – David C. Rankin Mar 04 '20 at 08:02

2 Answers2

2

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

There is no any undefined behavior. You simply delete a memory part which is pointed by the data pointer, and then you re-allocate a new array and assign it to data.

emrebaris
  • 59
  • 4