В C ++ 0x не инициализируют не статические инициализаторы членов данных неявный конструктор копирования? - PullRequest
14 голосов
/ 22 ноября 2011

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

В частности, я заметил, что с версией Apple clang 3.0 поведение меняется в зависимости от того, является ли структура (или класс) POD.

Следующая программа возвращает вывод «1», который указывает, что конструктор копирования игнорирует правую часть и вместо этого подставляет новый инициализатор нестатического члена данных (в этом примере логическое значение true для X :: а).

#include <iostream>
#include <string>

struct X
{
    std::string string1;
    bool a = true;
};

int main(int argc, char *argv[])
{
    X x;
    x.a = false;
    X y(x);
    std::cout << y.a << std::endl;
}

Однако, если вы закомментируете string1:

    // std::string string1;  

тогда поведение работает так, как я ожидал (вывод «0»), предположительно, потому что неявно не сгенерирован конструктор копирования, и, следовательно, данные копируются .

Действительно ли спецификация C ++ 0x предполагает, что было бы неплохо разрешить неявно определенному конструктору копирования не копировать содержимое правой части? Разве это не менее полезно и не интуитивно понятно? Я нахожу нестатическую функциональность инициализатора члена довольно удобной, но если это правильное поведение, я буду явно избегать этой функции из-за ее хитрого и неинтуитивного поведения.

Скажите, пожалуйста, что я не прав?

ОБНОВЛЕНИЕ: эта ошибка была исправлена ​​в исходном хранилище Clang. См. редакция .

ОБНОВЛЕНИЕ: эта ошибка, по-видимому, исправлена ​​в версии Apple clang 3.1 (tags / Apple / clang-318.0.45) (на основе LLVM 3.1svn). Эта версия clang была распространена как часть Xcode 4.3 для Lion.

1 Ответ

10 голосов
/ 22 ноября 2011

В конце концов, это не затенено, см. Выделенные части выдержки из стандартов:

Раздел по умолчанию для конструкторов копирования / перемещения (§ 12.8) слишком длинен для цитированияв целом.Суть в том, что нестатические поля-члены с инициализаторами все еще просто копируются конструктором копирования / перемещения по умолчанию

§ 12.8:

-6.Неявно определенный конструктор копирования / перемещения для класса X без объединения выполняет пошаговое копирование / перемещение своих баз и членов.[ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] Порядок инициализации такой же, как порядок инициализации баз и членов в определяемом пользователем конструкторе (см. 12.6.2).Пусть x будет либо параметром конструктора, либо, для конструктора перемещения, значением xvalue, ссылающимся на параметр.Каждый элемент базовых или нестатических данных копируется / перемещается способом, соответствующим его типу:

  • , если элемент является массивом, каждый элемент инициализируется напрямую с соответствующим подобъектом x;
  • если член m имеет rvalue ссылочный тип T &&, он инициализируется напрямую с помощью static_cast (xm);
  • в противном случае база или член инициализируются непосредственно с помощью соответствующей базы или члена x,Субъекты виртуального базового класса должны инициализироваться только один раз неявным образом заданным конструктором копирования / перемещения

Это пример, на который ссылаются:

struct A {
    int i = /* some integer expression with side effects */;
    A(int arg) : i(arg) { }
    // ...
};

(Int) конструктор просто инициализирует i значением arg, и побочные эффекты в скобках i-equalinitializer i не будут иметь места.—end example ]


Для полноты, соответствующий раздел в конструкторе по умолчанию по умолчанию:

§ 12.1

-6.Конструктор по умолчанию, который по умолчанию и не определен как удаленный, неявно определяется, когда он используется odr (3.2) для создания объекта своего типа (1.8) или когда он явно установлен по умолчанию после его первого объявления, Неявно определенный конструктор по умолчанию выполняет набор инициализаций класса, которые будут выполняться пользовательским конструктором по умолчанию для этого класса без ctor-initializer (12.6.2) и пустого составного оператора ,Если этот пользовательский конструктор по умолчанию будет неверно сформирован, программа будет некорректно сформирована.Если этот пользовательский конструктор по умолчанию будет удовлетворять требованиям конструктора constexpr (7.1.5), неявным образом заданным конструктором по умолчанию является constexpr.До того, как конструктор по умолчанию для класса определен неявно, все не предоставленные пользователем конструкторы по умолчанию для его базовых классов и его нестатических членов-данных должны быть неявно определены.[Примечание: неявно объявленный конструктор по умолчанию имеет спецификацию исключений (15.4).Определение с явным значением по умолчанию может иметь неявную спецификацию исключений, см. 8.4.—end note ]

...