Ошибка, когда есть частная копия ctor с открытым оператором присваивания - PullRequest
6 голосов
/ 13 октября 2009

Кто-нибудь из вас может объяснить, почему следующий фрагмент кода не компилируется?

#include <iostream>

using namespace std;

class Foo
{
public:
  Foo() { cout << "Foo::Foo()" << endl << endl; }
  Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
private:
  Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};

int main()
{
  Foo foo;

  foo = Foo();
}

Я получаю ошибку:

$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign
copy_ctor_assign.cc: In function 'int main()':
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private
copy_ctor_assign.cc:17: error: within this context

Примечание: когда я удаляю ключевое слово private: , код компилируется, но никогда не вызывается копия ctor Так почему же это ошибка, когда она приватная?

Не уверен, что это важно, но я использую:

$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.

Ответы [ 6 ]

5 голосов
/ 13 октября 2009

Вы инициализируете ссылку из временного.
Стандарт гласит:
Временное должно быть инициализировано (8.5.3, параграф 5) «используя правила для инициализации нереферентной копии (8.5)».

Конструкция копии временно удалена (разрешено стандартом. 12.8, п. 5).
Тем не менее, стандарт четко гласит (12.2 пар. 1):
«Даже когда избегают создания временного объекта (12.8), все семантические ограничения должны соблюдаться, как если бы временный объект был создан. [Пример: даже если конструктор копирования не вызывается, все семантические ограничения, такие как доступность (пункт 11), подлежит удовлетворению.] "

(также, при поиске правильной цитаты, нашел этот дубликат :)

Edit: добавление соответствующего местоположения из стандарта

4 голосов
/ 13 октября 2009

Этот код компилируется с gcc 4.3.3 и 4.4.1. Может быть, это просто ошибка в gcc 4.1?

3 голосов
/ 13 октября 2009

Предполагая, что код, который вы разместили, является единственным кодом в проекте, и нет скрытой передачи Foos по значению, происходящему где-либо, я могу только предположить, что gcc оптимизирует

Foo foo;
foo = Foo();

до

Foo foo = Foo();

... что несостоятельно, поскольку первая форма является конструкцией по умолчанию и присваиванием, а вторая эквивалентна

Foo foo(Foo());

... что явно является копией конструкции. Если я прав, конструктор копирования не запускается, потому что GCC может оптимизировать избыточный временный; это разрешено спецификацией C ++.

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

1 голос
/ 13 октября 2009

Копировать Ctor вызывается, когда:

  1. передача объекта по значению в качестве параметра функции,
  2. возвращение объекта из функции.

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

0 голосов
/ 13 октября 2009
#include <iostream>

using namespace std;

class Foo
{
public:
  Foo() { cout << "Foo::Foo()" << endl << endl; }
  Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
  Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};

int main()
{
  Foo f1;// default constructor called

  Foo f2 = f1; //copy constructor called
}

Проверьте это, в Foo f2=f1; (f2 создается с помощью конструктора копирования)

0 голосов
/ 13 октября 2009

Копируется конструктор, если вы напишите

Foo foo; // normal constructor
Foo foo1(foo); //copy constructor

В вашем случае сначала вызывается конструктор по умолчанию, а затем метод operator =.

...