Подтвердить что ты не робот

GCC 4.8 с GNU STL создает плохой код для конструктора std::string?

Итак, немного кода на С++:

void func( const std::string& theString )
{
    std::string theString( theString );
    theString += " more string";
    std::cout << theString;
}

который компилируется с помощью GCC 4.8 и VS 2013. Из моего знания на С++ код в порядке с локальной переменной theString, которая вводится в область видимости, которая затем скрывает theString от аргумента функции. В точке построения theString единственной theString в области видимости является аргумент функции, который передается конструктору std::string. Построенный std::string затем называется theString, который входит в область видимости и theString используется позже в коде. Уф!

Однако, GCC, похоже, действует как theString, переданный конструктору std::string, является локальным theString (который еще не сконструирован), в результате чего скомпилированная программа сбой. С VS 2013 код компилируется и работает нормально.

Итак,

  • Правильно ли мой код? Или я делаю что-то вне спецификации, что означает, что поведение GCC undefined.
  • Это ошибка в GCC?
4b9b3361

Ответ 1

Нет, ваш код недействителен.

В соответствии со стандартом С++ (пункт 3.3.2. декларации)

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

[ Example:
int x = 12;
{ int x = x; }

Здесь второй x инициализируется с его собственным (неопределенным) значением. -end пример]

И (3.3.3 Область блока, №2)

Имя параметра не должно быть обновлено в самом удаленном блоке определение функции или в самом внешнем блоке любого обработчика связанных с функцией-try-block.

Ответ 2

Это undefined поведение в С++. paxdiablo цитирует стандарт С++ 03:

Точка объявления для имени сразу после завершения declarator (раздел 8) и перед его инициализатором (если есть)...

Пример:

int x = 12;
{ int x = x; }

Здесь второй x инициализируется со своим (неопределенным) значением.

Ответ 3

Хотя текущие ответы в основном правильны, это поведение undefined, потому что вы используете неопределенное значение, детали немного более активны. Для примитивных типов я полагаю, что Инициализация подразумевает преобразование lvalue-to-rvalue? Is int x = x; UB? или Изменен ли стандарт С++ в отношении использования неопределенных значений и поведения undefined в С++ 1y?, чтобы понять, почему поведение undefined.

Для определенного пользователем типа, хотя я не думаю, что они заполняют достаточно деталей. Мы можем видеть из этого довольно старого, но релевантного отчет о дефекте 63: Инициализация класса из себя, который спрашивает:

И если да, то какова семантика самоинициализации UDT?

и дает пример, в котором используется только ссылка и адрес строящегося класса, и ответ отвечает:

3.8 basic.life, пункт 6, указывает, что ссылки здесь действительны. До этого ему разрешалось брать адрес объекта класса полностью инициализирован, и он разрешил передать его в качестве аргумента для опорный параметр, если ссылка может напрямую связываться.

Это относится к разделу 3.8 Object lifetime, потому что объект находится в разработке и его хранилище выделено, но его время жизни не началось, потому что его инициализация не завершена.

Если мы посмотрим на параграф 6 из раздела 3.8, он говорит (внимание мое):

Аналогично, до начала жизни объекта, но после хранилище, которое будет занимать объект, было или, после срок службы объекта закончился и перед хранилищем, которое объект, занятый, повторно используется или освобождается, любое значение gl, которое ссылается на оригинальный объект может использоваться, но только ограниченным образом. Для объекта под строительство или уничтожение, см. 12.7. В противном случае такое значение glvalue относится к выделенному хранилищу (3.7.4.2) и использует свойства glvalue, которые не зависят от его значения, четко определены. Программа имеет поведение undefined, если:

и включает в себя:

glvalue используется для доступа к нестатическому элементу данных или вызова нестатическая функция-член объекта,

Итак, до завершения инициализации мы не можем взять значение нестатического элемента данных, который явно понадобится при построении копирования a std::string.