CArray не вызывает конструкторы копирования при перераспределении памяти, что теперь? - PullRequest
2 голосов
/ 28 мая 2010

Предположим, у меня есть класс, требующий вызова конструктора копирования для создания правильной копии:

struct CWeird
{
    CWeird() { number = 47; target = &number; }

    CWeird(const CWeird &other) : number(other.number), target(&number) { }

    const CWeird& operator=(const CWeird &w) { number = w.number; return *this; }

    void output()
    {
        printf("%d %d\n", *target, number);
    }

    int *target, number;
};

Теперь проблема в том, что CArray не вызывает конструкторы копирования для своих элементов при перераспределении памяти (только memcpy из старой памяти в новую), например, этот код

CArray<CWeird> a;
a.SetSize(1);
a[0].output();

a.SetSize(2);
a[0].output();

Результаты в

47 47
-572662307 47

Я не понимаю этого. Почему std :: vector может правильно копировать одни и те же объекты, а CArray - нет? Какой урок здесь? Должен ли я использовать только классы, которые не требуют явных конструкторов копирования? Или это плохая идея использовать CArray для чего-то серьезного?

Ответы [ 2 ]

3 голосов
/ 28 мая 2010

Скопированный указатель по-прежнему указывает на исходный номер, который больше не существует, поскольку массив был перераспределен из-за изменения размера.

Я предполагаю, что CArray использует присваивание, а не копирование. Определите оператор присваивания, чтобы увидеть, исправляет ли это:

CWeird& operator=(CWeird w) { swap(w); return *this; }
void swap(CWeird& w) { int t = number; number = w.number; w.number = t; }

Как правило, это хорошая идея, чтобы избежать противоречивого поведения между копированием и назначением.

Кстати, в приведенном выше коде используется идиоматический подход к реализации семантики присваивания с надежными гарантиями исключительной безопасности:

  1. Возврат неконстантной ссылки во многом является стандартом для operator=, поскольку он соответствует семантике примитивных типов.
  2. Передача параметра по значению является самым простым способом сделать копию оригинала и гарантирует, что этот объект не будет затронут в случае сбоя конструктора копирования.
  3. Вызов swap переключает переданную копию с этим объектом таким образом, чтобы никогда не выдавать исключение, таким образом выполняя назначение полностью безопасным способом исключения.

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

0 голосов
/ 27 февраля 2015

Или это плохая идея использовать CArray для чего-то серьезного?

Да, это исключительно плохая идея. Используйте std::vector всякий раз, когда это возможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...