Самодельный уродливый вектор - PullRequest
0 голосов
/ 04 марта 2020

У меня есть некоторый обучающий пример самодельного вектора, это не шаблон для простоты:

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();
};

Оператор присваивания не реализован правильно:

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;
}

Как мы видим здесь, когда this == &other ( я не проверяю это условие с целью вопроса ), он удаляет свою собственную память ( конечно, это неправильно ), а затем перераспределяет новые строки в том же месте (data = new std::string[other.capacity];) строки не инициализируются, потому что конструктор по умолчанию вызывался во время operator new[], а затем копировал строки в себя (copy(other.begin(), other.end(), begin());).

Давайте представим, что потеря памяти не является проблема :-) Что-то шепчет мне, что копирование памяти в себя - неопределенное поведение, но я не уверен. Вопрос: есть ли неопределенное поведение?

Ответы [ 2 ]

2 голосов
/ 04 марта 2020

Если предположить, что data является действительным указателем или nullptr, то на самом деле UB вообще не существует.

С new std::string[other.capacity] вы создаете «массив» из default-initialized std::string объекты. Инициализированная по умолчанию (в основном построенная по умолчанию) std::string является допустимой, но пустой строкой.

Затем вы копируете этот массив пустых строк в себя, что нормально.


Что касается самокопирования, то оно похоже на

int a = 0;
a = a;

, что странно, но хорошо.

1 голос
/ 04 марта 2020

Нет неопределенного поведения. Вы просто удаляете часть памяти, на которую указывает указатель данных, а затем перераспределяете новый массив и присваиваете его данным.

...