2014-11-05 2 views
13

Так немного кода C++:GCC 4.8 с GNU STL создает плохой код для std :: string constructor?

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

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

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

Так,

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

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

+15

1. № 2. Нет. Вы инициализируете строку с ее (неинициализированным) я. – juanchopanza

+0

Таким образом, ошибка больше у VS2013, если она есть. Но ваш код неправильный. –

ответ

30

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

В соответствии со стандартом C++ (3.3.2 Точка декларации)

1 The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.

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

Here the second x is initialized with its own (indeterminate) value. —end example ]

И (3.3.3 Блок область применения, # 2)

A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block.

+2

Канонические вопросы для этого примера в «3.3.2»: для C++ 11 [Инициализация подразумевает преобразование lvalue-to-rvalue? Является 'int x = x;' UB?] (Http://stackoverflow.com/q/14935722/1708801) и для C++ 14 [Изменен стандарт C++ относительно использования неопределенных значений и неопределенного поведения в C++ 1y?] (http://stackoverflow.com/q/23415661/1708801) –

14

Это undefined behaviour in C++. paxdiablo цитирует стандарт C++ 03:

The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any) ...

Example:

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

Here the second x is initialized with its own (indeterminate) value.

2

Несмотря на то, текущие ответы в основном правильны, это неопределенное поведение, потому что вы используете неопределенное значение, детали немного более активны. Для примитивных типов я считаю, что Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB? или Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++1y? предоставляют достаточно подробностей, чтобы понять, почему поведение не определено.

Для определенного пользователем типа, хотя я не думаю, что они заполняют достаточно подробностей. Мы можем видеть из этого довольно старый, но отношение defect report 63: Initialization of class from self, который спрашивает:

And if so, what is the semantics of the self-initialization of UDT?

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

3.8 basic.life paragraph 6 indicates that the references here are valid. It's permitted to take the address of a class object before it is fully initialized, and it's permitted to pass it as an argument to a reference parameter as long as the reference can bind directly.

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

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

Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a glvalue refers to allocated storage (3.7.4.2), and using the properties of the glvalue that do not depend on its value is well-defined. The program has undefined behavior if:

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

the glvalue is used to access a non-static data member or call a non-static member function of the object,

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

 Смежные вопросы

  • Нет связанных вопросов^_^