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

StackOverflow https://stackoverflow.com/questions/1615660

  •  06-07-2019
  •  | 
  •  

Вопрос

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

#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" и не получил никакой диагностики.Почему здесь требуется доступ к конструктору копирования?Как я могу устранить предупреждение, помимо того, что делаю объект копируемым (что находится вне моего контроля) или создаю явную копию для передачи (когда копирование реального объекта обходится дорого)?

Это было полезно?

Решение

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

В противном случае создается временное хранилище типа “cv1 T1” и инициализируется из выражения инициализатора с использованием правил инициализации копии без ссылки (8.5).Затем ссылка привязывается к временному объекту.Если T1 связан со ссылкой на T2, cv1 должен иметь ту же cv-квалификацию, что и cv2, или большую cv-квалификацию, чем cv2;в противном случае программа будет неправильно сформирована.

Редактировать:перечитывая, я думаю, что 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

Другие советы

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

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

Я нутром чую, что Джерри ответ это правильно, но все еще есть несколько вопросов.

Что интересно, так это то, что существует ключевой вопрос , охватывающий предыдущий абзац этого раздела (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 temporary имеет тот же тип класса.Предыдущая формулировка содержала:

Если выражение инициализатора является значением 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) однако в данном случае у меня есть сомнения из-за несоответствия между различными вариантами поведения компилятора.

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

Thing temp (3);
<Код> показать (температура);

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top