Скрытый копирующий конструктор C ++ - PullRequest
0 голосов
/ 30 января 2012

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

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}

private:
    NotCopyable& operator=(const NotCopyable&);
    NotCopyable(const NotCopyable&);
    double _attr1;
    double _attr2;
};

Все в порядке, кроме случаев, когда я хочу присвоить массив:

NotCopyable arr[] =
{
    NotCopyable(1, 0),
    NotCopyable(2, 3)
};

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

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}
    NotCopyable(const NotCopyable&)
    {
        std::cout << "COPYING" << std:: endl;
    }
private:
    NotCopyable& operator=(const NotCopyable&);

    double _attr1;
    double _attr2;
};

Программа компилируется без ошибок, но конструктор копирования не вызывается. Итак, вопрос в том, как запретить копирование, но при этом можно назначать массивы?

Ответы [ 3 ]

7 голосов
/ 30 января 2012

Ваш код arr [] = { NotCopyable(1,2) }; запрашивает конструктор копирования, по крайней мере, формально. Практически копия обычно удаляется, но это подпадает под правило «как будто», и конструктор копирования все еще должен быть доступен, даже если в конечном итоге он не используется. (В GCC вы можете сказать -fno-elide-constructors, чтобы фактически вызвать конструктор копирования.)

Вы не можете решить эту проблему в C ++ 03, где инициализация скобки всегда требует формальной копии. В C ++ 11 вы можете использовать фигурную инициализацию для прямой инициализации членов массива, хотя:

NotCopyable arr[] { {1, 0}, {2, 3} };

Это работает даже при отсутствии доступного конструктора копирования.

1 голос
/ 30 января 2012

Это неверно, потому что вы используете массив объектов, которые должны быть созданы путем копирования:

#include <vector>
using namespace std;

class NotCopyable
{
public:
    NotCopyable(const double& attr1, const double& attr2) : _attr1(attr1), _attr2(attr2) {}
    ~NotCopyable(void) {}

private:
    NotCopyable& operator=(const NotCopyable&);
    NotCopyable(const NotCopyable&);
    double _attr1;
    double _attr2;
};

int main()
{
    vector<NotCopyable> v;
    NotCopyable a(1, 2);
    v.push_back(a); // THIS IS COPYING
    return 0;
}

Поскольку вы отключили копирование, вы можете хранить только ссылки.Вы должны сделать это массивом указателей :

NotCopyable a(1, 2);

// incorrect:
vector<NotCopyable> v;
v.push_back(a);

// correct:
vector<NotCopyable*> v2;
v2.push_back(&a);

Надеюсь, это поможет;)

0 голосов
/ 30 января 2012
NotCopyable arr[] =
{
    NotCopyable(1, 0),
    NotCopyable(2, 3)
};

Когда вы пишете это, компилятору нужен конструктор копирования, так как это copy-initialization .Вот почему вы получаете ошибку компиляции, так как конструктор копирования объявлен private, и поэтому он недоступен извне.Однако, если вы определите его в разделе public, он будет работать, но конструктор копирования не вызывается, что связано с оптимизацией, выполненной компилятором.Спецификация позволяет компилятору исключить вызов конструктора копирования в такой ситуации, однако ему все еще требуется доступный конструктор копирования только для семантической проверки кода.На самом деле он не вызывается после завершения семантической проверки!

...