Нарезка объектов с помощью частного конструктора копирования в производном классе в C ++ - PullRequest
2 голосов
/ 20 августа 2009

Предположим, у меня есть что-то вроде следующего в test.cxx (и что я делаю объект нарезки на 1 намеренно):

class A {
};

class B : public A {
  // prevent copy construction and assignment
  B(const B& other);
  B& operator=(const B& other);
public:
  explicit B(){}
};

class C {
  A m_a;
public:
  explicit C() : m_a( B() ) {} // 1
};

Я ожидаю, что это сработает, так как в 1 должен быть вызван конструктор копирования класса A (здесь он генерируется компилятором и общедоступен). Этот код также прекрасно компилируется на последних компиляторах (я пробовал g ++ - 4.4 и Intel 11.0), однако более старые компиляторы (такие как g ++ - 4.2 и g ++ - 4.0) пытаются вызвать конструктор копирования B, который я объявил закрытым, в результате:

test.cxx: In constructor ‘C::C()’:
test.cxx:7: error: ‘B::B(const B&)’ is private
test.cxx:16: error: within this context

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

Редактировать : Извините, компилятор Intel версии 10.1 и 11.0 выдает следующее: предупреждение # 734: "B :: B (const B &)" (объявлено в строке 6) ), требуется для копии, которая была удалена, недоступна

Ответы [ 5 ]

4 голосов
/ 20 августа 2009

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

class A {
};

class B : public A {
  B(const B& other);
  B& operator=(const B& other);
public:
  explicit B(){}
};

int main()
{
    A const & a = B();
}

Согласно 8.5.3 / 2, «[...] передача аргумента (5.2.2) и возврат значения функции (6.6.3) являются инициализациями», и поэтому код должен быть некорректным.

Редактировать: Я до сих пор твердо верю, что код неправильно сформирован в соответствии с C ++ 03. Тем не менее, я только что прочитал соответствующий раздел рабочего проекта для C ++ 0x, и кажется, что он больше не требует наличия конструктора копирования. Возможно, именно поэтому ваш код начал компилироваться, когда вы перешли с gcc-4.2 на gcc-4.3.

Редактировать: Чтобы уточнить, причина, по которой B::B(const B &) должен быть доступен, связана с привязкой B() к первому параметру A::A(const A &) (который, конечно, вызывается, когда m_a инициализируется).

Редактировать: Что касается разницы между C ++ 03 и C ++ 0x, litb был достаточно любезен, чтобы найти соответствующий отчет о дефектах .

1 голос
/ 20 августа 2009

Я думаю, что это стандартный код в C ++ 0x, но не в C ++ 03.

Я бы назвал этот тест чем-то вроде "скопировать конструкцию из rvalue".

Это было сообщено как ошибка, но gcc люди утверждают здесь , что является правильным поведением и дают ссылки на стандарт.

[dcl.init.ref] / 5, пул 2, подпункт 1

Если выражение инициализатора в rvalue, с T2 тип класса, и "cv1 T1 "является эталонно-совместимым с" cv2 T2 "ссылка связана в одном из следующие способы (выбор реализация определена):
- Ссылка привязана к объекту, представленному значением r (см. 3.10) или подобъект в этом объекте.
- Создан временный тип "cv1 T2" [sic], а конструктор вызывается для копирования всего значения объект во временный. ссылка связана с временным или подобъекту во временном.

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

Стандарт C ++ 0x устраняет неоднозначность, и ссылка всегда привязана к объекту, представленному значением r, без необходимости конструктора быть доступным.

1 голос
/ 20 августа 2009

Похоже, что старые компиляторы g ++ не могут передавать временные объекты по ссылке, если нет доступного конструктора копирования:

class A { 
  A(const A& other);
  A& operator=(const A& other);
public:
  explicit A(){}
};
void f( const A& a ) {}
int main() {
  A a;
  f( a );    // fine
  f( A() );  // fails
}
0 голосов
/ 20 августа 2009

Это действительно. Вызов B () создает объект B; Публичный конструктор, сгенерированный компилятором по умолчанию, называется.

Когда будет создан объект C, будет создан объект A. Так как это значение, то будет рассматриваться статическая типизация, и на любом объекте, который является производным от A и используется для копирования, создается объект A. Класс A имеет открытый конструктор копирования, предоставляемый компилятором. Компилятор видит, что объект B также имеет тип A. Компилятор занимается только копированием, создающим объект A, и он знает, что может это сделать, поэтому он копирует объект A в объекте B с помощью конструктора A копирования в C: : m_a объект. т.е. нарезка из-за статической типизации.

Поучительно посмотреть на память об этих объектах. Поместите элемент данных char * в A, инициализированный как «I'm A», и элемент данных char * в B, инициализированный как «I'm a B», и пройдите через ваш отладчик, чтобы отслеживать ваши объекты. Вы должны увидеть эти строки достаточно просто.

0 голосов
/ 20 августа 2009

Я не могу указать вам на определенный раздел стандарта, но он, конечно, выглядит нормально для меня и компилируется с Comeau C ++ , а также с компиляторами, которые вы упомянуть. Что касается названия для такого теста, я думаю, что «совместимость компилятора» так же хороша, как и все остальные.

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