Область видимости C++11 и время жизни временной привязки к (const) ссылке (GCC)

У меня есть следующие вопросы, связанные с той же ситуацией (не в целом):

  • Почему компилятор не выдает предупреждение, когда временный объект связан со ссылкой?
  • Как продлевает жизнь временную работу (когда она привязана к ссылке)?
  • Как интерпретировать / понять стандарт C++ (C++11)?
  • Это ошибка (в компиляторе)? Должно ли это быть?

Итак, вот о чем мы говорим:

struct TestRefInt {
    TestRefInt(const int& a) : a_(a) {};
    void DoSomething() {    cout << "int:" << a_ << endl;  }
protected:
    const int& a_;
};

Должен TestRefInt tfi(55); а также tfi.DoSomething(); Работа? Как и где? Так вот код

TestRefInt tfi(55);

int main() {
    TestRefInt ltfi(8);

    tfi.DoSomething();
    ltfi.DoSomething();
    return 0;
}

Что это должно сделать?

Здесь я разработаю еще немного.

Рассмотрим этот реальный (упрощенный) пример. Как это выглядит для начинающего программиста C++? Имеет ли это смысл?

(вы можете пропустить код, проблема та же, что и выше)

#include <iostream>
using namespace std;

class TestPin //: private NonCopyable
{
    public:
        constexpr TestPin(int pin) : pin_(pin) {}
        inline void Flip()   const {
            cout << " I'm flipping out man : " << pin_ << endl;
        }
    protected:
        const int pin_;
};

class TestRef {
public:
    TestRef(const TestPin& a) : a_(a) {};
    void DoSomething() {    a_.Flip();  }
protected:
    const TestPin& a_;
};

TestRef g_tf(1); 

int main() {
    TestRef tf(2);

    g_tf.DoSomething();
    tf.DoSomething();

    return 0;
}

Командная строка:

/** Compile:
Info: Internal Builder is used for build
g++ -std=c++11 -O0 -g3 -Wall -Wextra -Wconversion -c -fmessage-length=0 -o "src\\Scoping.o" "..\\src\\Scoping.cpp" 
g++ -o Scoping.exe "src\\Scoping.o" 
13:21:39 Build Finished (took 346ms)
 */

Выход:

/** 
 I'm flipping out man : 2293248
 I'm flipping out man : 2
 */

Проблема:TestRef g_tf(1); /// shouldn't the reference to temporary extend it's life in глобальный охват тоже?

Что говорит стандарт?

От того, как auto&& продлит срок службы временного объекта?

Обычно временный объект длится только до конца полного выражения, в котором он появляется. Однако C++ намеренно указывает, что связывание временного объекта со ссылкой на const в стеке удлиняет время жизни временного объекта до времени жизни самой ссылки.

  ^^^^^

Глобалы не размещаются в стеке, поэтому время жизни не увеличивается. Однако компилятор не выдает никаких предупреждений! Не должно ли это по крайней мере сделать это?

Но моя главная мысль: с точки зрения удобства использования (имеется в виду, как пользователь C++, GCC как программист) было бы полезно, если бы тот же принцип был распространен не только на стек, но и на глобальную область, продлевая время жизни (делая глобальный временные "постоянные").

Sidenote: Проблема еще более осложняется тем, что TestRef g_tf(1); действительно TestRef g_tf{ TestPin{1} }; но временный объект не виден в коде, и, не глядя на объявление конструктора, он выглядит так, будто конструктор вызывается целым числом, и это редко приводит к возникновению такого рода ошибок.

Насколько я знаю, единственный способ решить эту проблему - запретить временные файлы при инициализации, удалив TestRefInt(const int&& a) =delete; конструктор. Но это также запрещает это в стеке, где продление жизни работало.

Но предыдущая цитата не совсем соответствует стандарту C++ 11. Соответствующие части стандарта C++ 11 - 12.2 p4 и p5:

4. Существуют два контекста, в которых временные уничтожаются в другой точке, чем конец полного выражения. Первый контекст [...]

5 - Второй контекст, когда ссылка связана с временным. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:

- Временная привязка к элементу ссылки в ctor-initializer конструктора (12.6.2) сохраняется до выхода из конструктора.

- временная граница с опорным параметром в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов. § 12,2 245 с ИСО / МЭК N3337

- Срок действия временной привязки к возвращенному значению в операторе возврата функции (6.6.3) не продлевается; временное уничтожается в конце полного выражения в операторе возврата.

- Временная привязка к ссылке в новом инициализаторе (5.3.4) сохраняется до завершения полного выражения, содержащего новый инициализатор. [Пример: struct S { int mi; const std::pair& mp; }; S a { 1, {2,3} }; S* p = новый S{ 1, {2,3} }; // Создает висячую ссылку - конец примера] [Примечание: это может привести к появлению висячей ссылки, и реализации рекомендуется выдавать предупреждение в таком случае. - конец примечания]

Мой английский и понимание стандарта недостаточно хороши, так что же это за исключение? "- Временная привязка к элементу ссылки в ctor-initializer конструктора (12.6.2) сохраняется до выхода из конструктора". Или "параметр ссылки в вызове функции" не упоминает ничего о распределении в стеке или в глобальной области видимости. Другие исключения, похоже, не применяются. Я ошибся?

Кто это, или никто из них?

У нас есть временный вызов функции (конструктор), а затем ссылка на временный объект привязывается к ссылке на член в инициализаторе. Это неопределенное поведение? Или исключение все еще применяется, а временное должно быть уничтожено? (или оба)

Как насчет этого?

struct TestRefIntDirect {
    TestRefIntDirect(int a) : a_(a) {};
    void DoSomething() {    cout << "int:" << a_ << endl;  }
protected:
    const int& a_;
};

Еще одна ссылка, такое же поведение.

Почему это работает в одном случае (создание экземпляра внутри функции) по сравнению с другим случаем (в глобальной области видимости)?

Разве GCC не "уничтожает" одного из них "случайно"?

Насколько я понимаю, ни один из них не должен работать, временный не должен сохраняться, как говорит стандарт. Кажется, что GCC просто "позволяет" вам получить доступ к не сохраняющимся объектам (иногда). Я предполагаю, что стандарт не определяет, о чем должен предупреждать компилятор, но можем ли мы согласиться с этим? (в других случаях он предупреждает о "возврате ссылки на временный объект"). Я думаю, что и здесь.

Это ошибка или, может быть, где-то должен быть запрос функции?

Мне кажется, что GCC говорит: "Ну, ты не должен трогать это печенье, но я оставлю его здесь для тебя и не буду никого предупреждать об этом".… Что мне не нравится.

Эту вещь другие ссылки на стек я не нашел в стандарте, откуда она взялась? Это дезинформация о стандарте? Или это следствие чего-то в стандарте? (Или это просто совпадение реализации, что временный объект не перезаписан и на него можно ссылаться, потому что он оказался в стеке? Или это поведение, определяемое компилятором, расширение?)

Чем больше я знаю C++, тем больше кажется, что каждый день он вручает мне пистолет, чтобы выстрелить себе в ногу с ним…

Я хотел бы получить предупреждение от компилятора, если я делаю что-то не так, чтобы я мог это исправить. Неужели я прошу так много?

Другие связанные посты:

Временное продление жизни

C++: постоянная ссылка на временный

Продлевает ли константная ссылка временную жизнь?

Возврат временного объекта и привязка к константной ссылке

Я не хотел так много писать. Если вы все прочитали, спасибо.

0 ответов

Другие вопросы по тегам