Почему это предупреждение от компилятора IBM XL C / C ++?

Вот минимальный пример кода, иллюстрирующий проблему:

#include <iostream>

class Thing
{
   // Non-copyable
   Thing(const Thing&);
   Thing& operator=(const Thing&);

   int n_;

public:
   Thing(int n) : n_(n) {}

   int getValue() const { return n_;}
};

void show(const Thing& t)
{
   std::cout << t.getValue() << std::endl;
}

int main()
{
   show(3);
}

Это дает ту же ошибку:

int main()
{
    show( Thing(3) );
}

Компилятор IBM XL C / C ++ 8.0 под AIX выдает следующие предупреждения:

"testWarning.cpp", line 24.9: 1540-0306 (W) The "private" copy constructor "Thing(const Thing &)" cannot be accessed.
"testWarning.cpp", line 24.9: 1540-0308 (I) The semantics specify that a temporary object must be constructed.
"testWarning.cpp", line 24.9: 1540-0309 (I) The temporary is not constructed, but the copy constructor must be accessible.

Я также пробовал g ++ 4.1.2 с "-Wall" и "-pedantic" и не получил диагностики. Почему здесь требуется доступ к конструктору копирования? Как я могу устранить предупреждение, помимо того, чтобы сделать объект копируемым (что находится вне моего контроля) или сделать явную копию для передачи (когда копирование реального объекта дорого)?


person Fred Larson    schedule 23.10.2009    source источник
comment
Вы действительно используете этот конструктор копирования где-нибудь в реализации класса?   -  person Clay Fowler    schedule 24.10.2009
comment
Нет. Я опубликовал весь файл кода, с помощью которого была произведена диагностика.   -  person Fred Larson    schedule 24.10.2009
comment
К вашему сведению: я также пробовал с VC ++ 2005 и 2008, компилируется без предупреждений. Так что, похоже, вы правы, проблема скорее связана с компилятором IBM   -  person jdehaan    schedule 24.10.2009


Ответы (4)


Правила для этого приведены в §8.5.3 / 5 стандарта. Выделяют три основные ситуации. В первом случае инициализатор (в вашем случае «3») является либо lvalue, либо имеет тип класса. Поскольку ни один из них не соответствует действительности, у вас есть третий случай: инициализация ссылки на константу с помощью rvalue, не имеющего типа класса. Этот случай охвачен последним пунктом в 8.5.3 / 5:

Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy initialization (8.5). The reference is then bound to the temporary. If T1 is reference-related to T2, cv1 must be the same cv-qualification as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed.

Изменить: перечитывая, я думаю, что IBM права. Раньше я думал о возможности копирования временного, но проблема не в этом. Чтобы создать временную, используя инициализацию не ссылочной копии, как указано в §8.5, ей нужен ctor копии. В частности, на данный момент это эквивалентно выражению вроде:

T x = a;

Это в основном эквивалентно:

T x = T(a);

Т.е. требуется создать временное, а затем скопировать временное в инициализируемый объект (который в данном случае также является временным). Подводя итог необходимому процессу, он примерно эквивалентен коду вроде:

T temp1(3);
T temp2(temp1); // requires copy ctor
show(temp2);    // show's reference parameter binds directly to temp2
person Jerry Coffin    schedule 23.10.2009
comment
Хорошая информация. Спасибо за исследование, Джерри. - person Fred Larson; 24.10.2009
comment
Это действительно странно, но я согласен с вашим / IBM прочтением стандарта. - person David Seiler; 24.10.2009
comment
‹Quote› необходимо создать временное ‹/quote› Технически: необходимо иметь возможность создавать временные. Технически компилятор может это оптимизировать. - person Martin York; 24.10.2009
comment
@Martin: ну да, все требования включают неявное: или что-то подобное, если они действительно эквивалентны тому, что вы не можете отличить от соответствующего кода. - person Jerry Coffin; 24.10.2009
comment
То, что вы здесь говорите, имеет смысл. Единственная проблема, с которой я столкнулся, заключается в том, что последние версии g ++ и comeau отклоняют Thing t = 3, но принимают show (3). Это не значит, что то, что вы говорите, неправильно, но особенно то, что Комо не соответствует поведению, заставляет меня задуматься ... - person Richard Corden; 26.10.2009
comment
Я не могу гарантировать этого ни в коем случае, но предполагаю, что Comeau уже реализует что-то более близкое к правилам в текущем проекте C ++ 0x. Добавление ссылок rvalue (в частности) означает, что правила инициализации (особенно ссылок) были существенно переписаны. - person Jerry Coffin; 26.10.2009
comment
Только что посмотрел черновик от июня 2009 г., и этот раздел не сильно изменился (за исключением добавления 391). Это был бы интересный вопрос о comp.std.c ++ или о том, есть ли у вас доступ к основному отражателю. - person Richard Corden; 27.10.2009

C ++ позволяет достаточно умным компиляторам избегать копирования временных объектов - единственного нарушения правила as-if, разрешенного стандартом. Я не знаком с компилятором IBM AIX C ++, но похоже, что он думает, что вызов show(3) требует копирования временного объекта Thing. В этом случае C ++ требует, чтобы у вас был доступный конструктор копирования, даже если ваш компилятор достаточно умен, чтобы его не использовать.

Но почему show(3) вообще требует копию? Этого я не могу понять. Если повезет, Litb скоро будет рядом.

person David Seiler    schedule 23.10.2009
comment
Это примерно то, о чем я думал. - person Fred Larson; 24.10.2009
comment
Но почему для show (3) вообще требуется копия? Я не думаю, что так должно быть. Код должен создать временный объект и связать его прямо с параметром функции const Thing&. Так что я думаю, что Джерри прав: это ошибка. - person sbi; 24.10.2009
comment
Я передумал - перечитав стандарт, я почти уверен, что это не ошибка. - person Jerry Coffin; 24.10.2009

Мне кажется, что ответ Джерри правильно, но есть еще несколько вопросов.

Интересно то, что существует основная проблема, охватывающая предыдущий абзац этого раздела (391). Эта проблема связана с тем, что аргумент относится к тому же типу класса. Конкретно:

int main () {
  show ( Thing (3) );       // not allowed under current wording
                            // but allowed with Core Issue 391

  show ( 3 );               // Still illegal with 391
}

Изменение в основной проблеме 391 влияет только на где временное значение rvalue имеет тот же тип класса. В предыдущей редакции было:

Если выражение инициализатора является rvalue, где T2 - тип класса, а cv1 T1 совместим по ссылкам с cv2 T2,, ссылка привязывается следующим образом:

[...]

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

Эта последняя строка делает show(Thing(3)) незаконным в соответствии с текущим стандартом. Предлагаемая формулировка этого раздела:

Если выражение инициализатора является rvalue, где T2 - тип класса, а cv1 T1 совместим по ссылкам с cv2 T2, ссылка привязывается к объекту, представленному rvalue (см. 3.10 [basic.lval]) или к под- объект внутри этого объекта.

На этом этапе я подумал, что g ++, возможно, обновил свое поведение согласно 391, но это изменение случайно коснулось случая инициализации копирования. Однако это не демонстрируется версиями g ++, которые я тестировал:

class A{
public:
  A ();
  A (int);
private:
  A (A const &);
};

void foo (A const &);

void foo ()
{
  A a = 3 ;     // 3.2.3 (ERROR), 3.4.6(ERROR), 4.4.0(ERROR), Comeau(ERROR)
  
  foo ( 3 ) ;   // 3.2.3 (OK), 3.4.6(OK), 4.4.0(OK), Comeau(OK)
  foo ( A() );  // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
  foo ( A(3) ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
}

Я не могу придраться к интерпретации Джерри случая foo (3), однако у меня есть сомнения из-за несоответствия между различными поведениями компилятора.

person Richard Corden    schedule 26.10.2009

Что произойдет, если вы попытаетесь назвать временную вещь?

Thing temp(3);
show(temp);

person user200783    schedule 23.10.2009
comment
Это устраняет сообщения. Мы, вероятно, сделаем это по существу, но, вероятно, с выделением кучи. Это не так быстро, но реальный объект довольно велик, чтобы помещать его в стек. Так что, может быть, все равно лучше не полагаться на временное. - person Fred Larson; 24.10.2009