Легенда о константной ссылке.

Уже несколько раз в кругах C++ разработчиков слышал Легенду о константной ссылке. Легенда варьируется от “из функции можно вернуть константную ссылку на временный объект” до “можно сохранить константную ссылку на временный объект”. Как раз на прошлой неделе мы обсудили этот вопрос с коллегами, и мне захотелось в нем детально разобраться.
В стандарте данная ситуация освещена очень вскользь, так что пришлось покопаться. Во-первых, в пункте 12.2.5 сказано следующее:

A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call. A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits. In all these cases, the temporaries created during the evaluation of the expression initializing the reference, except the temporary to which the reference is bound, are destroyed at the end of the full-expression in which they are created and in the reverse order of the completion of their construction.

Таким образом, первая версия легенды не верна. Идем дальше:

the expression const C& cr = C(16)+C(23); creates three temporaries. A first temporary T1 to hold the result of the expression C(16), a second temporary T2 to hold the result of the expression C(23), and a third tempo- rary T3 to hold the result of the addition of these two expressions. The temporary T3 is then bound to the reference cr. It is unspecified whether T1 or T2 is created first. On an implementation where T1 is cre- ated before T2, it is guaranteed that T2 is destroyed before T1. The temporaries T1 and T2 are bound to the reference parameters of operator+; these temporaries are destroyed at the end of the full expression containing the call to operator+. The temporary T3 bound to the reference cr is destroyed at the end of cr’s lifetime, that is, at the end of the program.

Так что вторая версия легенды похожа на правду. А теперь небольшой тест:

#include <iostream>

class TestClass
{
public:
    TestClass()
    {
        std::cout << "Ctor" << std::endl;
    }
    ~TestClass()
    {
        std::cout << "Dtor" << std::endl;
    }
    void Foo() const
    {
        std::cout << "Foo" << std::endl;
    }
};

const TestClass MakeConstRef()
{
    TestClass testData;
    return testData;
}

int main()
{
    std::cout << "Start test" << std::endl;

    const TestClass& test = MakeConstRef();
    test.Foo();

    std::cout << "Stop test" << std::endl;
    return 0;
}

Компилируем, запускаем, смотрим результат:

astavonin:/Users/../const_ref: clang -lstdc++ main.cpp
astavonin:/Users/../const_ref: ./a.out
Start test
Ctor
Foo
Stop test
Dtor

4 Comments Легенда о константной ссылке.

  1. agronom

    есть еще такой баг (из книги Стефана Дьюхерста)
    short s=123;
    const int& r = s; // формируется временный обьект
    s= 12345; // r не меняется

    Reply
  2. Alexander Stavonin

    Тут одно из двух, либо Стефан не читал стандарта, либо ты не так понял его книгу. Дело в том, что в приведенном примере будет создана копия объекта s и ссылка на эту копию сохранена в r. Описано в стандарте, пункт 8.5.3(5)

    Reply
  3. agorikov

    мне больше интересно- какие параллели/аналогии и различия между Obj C, С++ и Java. Как реализовать паттерны типа фабрики, фасада, абстрактной фабрики на этих 3 языках.

    Reply
  4. Alexander Stavonin

    Ну, написать про Java я явно ничего не смогу, т.к. я ее просто не знаю. Но если говорить про паттерны распространенные в Objective-C, то наиболее часто встречающиеся это KVO и KVC. Про них я вот тут писал, кстати: http://stavonin.blogspot.com/2010/11/objective-c.html

    Reply

Leave a Reply