Ссылка на ту же переменную, которую вы объявляете

#c #construction

#c #строительство #c #построение

Вопрос:

Я пару раз видел следующую ошибку типа при работе с кодом C :

 QString str = str.toUpper();
  

Это может быть довольно простой ошибкой, и все же она компилируется и выполняется (иногда со сбоями, иногда без). Я не вижу никаких обстоятельств, при которых это было бы тем, что вы действительно хотели бы сделать.

Некоторые тесты показали, что вызывается конструктор копирования, а не конструктор по умолчанию, и что объект передается сам из конструктора копирования.

Кто-нибудь может объяснить, почему это не ошибка компилятора или даже не предупреждение?

Комментарии:

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

2. Возможно, потому, что компилятор не знает, что ToUpper() возвращает тот же экземпляр? Я могу себе представить, что разработчикам компилятора очень сложно это проверить.

3. @MarkB: это определенное поведение, см. Мой ответ.

Ответ №1:

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

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

Например int x = f(x); , полностью корректно, если int f(const intamp;) не использует значение своего параметра. Как компилятор узнает об этом, если он еще не видел тело функции?

Комментарии:

1. Это имеет смысл. Я думаю, я бы сказал (ради здравомыслия, если ничего другого), что вызов f(x) для x, который еще не был создан, все равно должен быть ошибкой, поскольку, как вы упомянули, единственный сценарий, в котором это было бы безопасно, — это тот, в котором функция его не использует.

2. Ах да, но функция может записывать в нее, что на самом деле нормально для встроенных типов.

3. Стоит отметить, что этот синтаксис специально запрещен, когда объект определяется с помощью auto ключевого слова, но по причинам вывода типа. auto x = x 1; недопустимо, и совместимые компиляторы должны отклонить его.

4. @Chris — На самом деле это может сохранить указатель или ссылку на объект и использовать его позже . Он просто не может использовать значение (поскольку его еще нет). C и C известны тем, что не запрещают вещи, которые только отдаленно полезны.

5. Итак, что именно представляет собой состояние x при знаке равенства? Какой конструктор был вызван в этот момент?

Ответ №2:

Ошибки или предупреждения нет, потому что это эквивалентно:

 QString str;
str = str.toUpper();
  

Точно так же, как

 QString str = "aaa";
  

такое же, как

 QString str;
str = "aaa";
  

Чтобы сделать это в том же операторе, вам нужно использовать конструктор, который не будет компилироваться:

 QString str(str.toUpper());
  

точно так же, как:

 QString str("aaa");
  

не эквивалентно

 QString str;
str = "aaa";
  

Комментарии:

1. Это определенно не эквивалентно QString str; str = str.toUpper(); тому, что просто like QString str = "aaa"; не вызывает оператор присваивания.

2. Являются QString str = "aaa"; и QString str; std = "aaa" на самом деле одинаковыми? Я не эксперт по C , но мне кажется, что первый вызывает конструктор, а второй вызывает конструктор по умолчанию, а затем operator= . Codepad , похоже, согласен.

3. -1: QString str = "aaa" не будет вызывать конструктор по умолчанию. Он вызовет конструктор, который принимает a const char* , и аргументом этого конструктора будет "aaa" . То есть это не то же самое, что по умолчанию создавать QString , а затем копировать-присваивать ему.

4. @NicolBolas: он также вызовет конструктор копирования. Этот вызов может быть опущен, однако синтаксис QString str = «aaa» требует доступного конструктора копирования независимо от того, пропущен фактический вызов или нет