2013-06-21 10 views
5

попросив this question, я узнал константную ссылку на временный объект является действительным в C++:константной ссылка на временный объект становится сломана после области видимости функции (время жизни)

int main() 
{ 
    int a = 21; 
    int b = 21; 

    //error: invalid initialization of non-const reference 
    //int  & sum = a + b;e [...] 

    //OK 
    int const & sum = a + b; 

    return sum; 
} 

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

#include <string> 
#include <map> 

struct A 
{ 
    // data 
    std::map <std::string, std::string> m; 
    // functions 
    const A& nothing()   const { return *this; } 
    void init()      { m["aa"] = "bb"; } 
    bool operator!= (A const& a) const { return a.m != m; } 
}; 

int main() 
{ 
    A a; 
    a.init(); 

    A const& ref = A(a); 
    A const& refnop = A(a).nothing(); 

    int ret = 0; 
    if (a != ref)  ret += 2; 
    if (a != refnop) ret += 4; 

    return ret; 
} 

Протестировано с использованием GCC 4.1.2 и MSVC 2010, оно возвращает 4;

$> g++ -g refnop.cpp 
$> ./a.out ; echo $? 
4 

Разница между ref и refnop является вызов nothing(), который не делает ничего на самом деле. Кажется, после этого вызова временный объект уничтожается!

Мой вопрос:
Почему в случае refnop, время жизни временного объекта не совпадает с его константной ссылке?

+0

Внимание: с помощью G ++ версии 4.4 и 4.6, этот фрагмент возвращает 0 ... – olibre

ответ

9

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

Случай, озадачивает вас

A const& refnop = A(a).nothing(); 

похож на этот случай:

A const& foo(A const& bar) 
{ 
    return bar; 
} 
//... 
A const& broken = foo(A()); 

В обоих случаях временная получает связанный с функцией аргумента (неявной this для nothing(), bar для foo()) и получает его время жизни «расширен» до времени жизни аргумента функции. Я помещал «расширенный» в кавычки, потому что естественное время жизни временного уже больше, поэтому фактическое расширение не происходит.

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

1

Мой оригинальный пример сложный.

Поэтому я публикую здесь более простой пример, и я предоставляю соответствующий пункт ISO C++ standard.

Этот простой пример также доступен на coliru.stacked-crooked.com/

#include <iostream> 

struct A 
{ 
    A(int i) { std::cout<<"Cstr "<< i<<'\n'; p = new int(i); } 
~A()  { std::cout<<"Dstr "<<*p<<'\n'; delete p;  } 

    const A& thiz() const { return *this; } 

    int *p; 
}; 

const A& constref(const A& a) 
{ 
    return a; 
} 

int main() 
{ 
    const A& a4 = A(4); 
    const A& a5 = A(5).thiz(); 
    const A& a6 = constref(A(6)); 

    std::cout << "a4 = "<< *a4.p <<'\n'; 
    std::cout << "a5 = "<< *a5.p <<'\n'; 
    std::cout << "a6 = "<< *a6.p <<'\n'; 
} 

Выходной сигнал с помощью командной строки g++-4.8 -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out:

Cstr 4 
Cstr 5 
Dstr 5 
Cstr 6 
Dstr 6 
a4 = 4 
a5 = 0 
a6 = 0 
Dstr 4 

Как вы можете видеть, временные объекты, на которые ссылается a5 и a6 разрушаются на конец функций thiz и constref соответственно.

Это экстракт §12.2 временных объектов, где жирным шрифтом часть относится в данном случае:

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

  • Временной границы с опорным элементом в конструкторе ctor-initializer (12.6.2) сохраняется, пока конструктор не выйдет.
  • Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.
  • Срок службы временной привязки к возвращаемому значению в : оператор возврата функции (6.6.3) не продлевается; временный уничтожается в конце полного выражения в операторе return.
  • Временная граница к ссылке в нового-инициализаторе (5.3.4) не сохраняется до завершения полного выражения, содержащего нового инициализатора-.

Это более полный пример:

#include <iostream> 

struct A 
{ 
    A()   { std::cout<<"Cstr 9\n";   p = new int(v = 9);  } 
    A(int i) { std::cout<<"Cstr "<<i<<'\n'; p = new int(v = i);  } 
    A(const A&o){ std::cout<<"Copy "<<o.v<<'\n'; p = new int(v = 10+o.v); } 
    ~A()   { std::cout<<"Del "<<v<<' '<<*p<<'\n'; *p = 88; delete p; } 

    const A& thiz() const { return *this; } 

    int *p; 
    int v; 
}; 

const A& constref(const A& a) 
{ 
    return a; 
} 

std::ostream& operator<<(std::ostream& os, const A& a) 
{ 
    os <<"{ *p="<< *a.p <<" , v="<< a.v <<" }\n"; 
    return os; 
} 

int main() 
{ 
    std::cout << "---const A a1 = A(1)"    "\n"; 
        const A a1 = A(1); 
    std::cout << "---const A a2 = A(2).thiz()"   "\n"; 
        const A a2 = A(2).thiz(); 
    std::cout << "---const A a3 = constref(A(3))" "\n"; 
        const A a3 = constref(A(3)); 
    std::cout << "---const A& a4 = A(4)"    "\n"; 
        const A& a4 = A(4); 
    std::cout << "---const A& a5 = A(5).thiz()"   "\n"; 
        const A& a5 = A(5).thiz(); 
    std::cout << "---const A& a6 = constref(A(6))" "\n"; 
        const A& a6 = constref(A(6)); 

    std::cout << "a1 = "<< a1; 
    std::cout << "a2 = "<< a2; 
    std::cout << "a3 = "<< a3; 
    std::cout << "a4 = "<< a4; 
    std::cout << "a5 = "<< a5; 
    std::cout << "a6 = "<< a6; 
} 

и соответствующий выход, используя тот же g++ командной строки:

---const A a1 = A(1) 
Cstr 1 
---const A a2 = A(2).thiz() 
Cstr 2 
Copy 2 
Del 2 2 
---const A a3 = constref(A(3)) 
Cstr 3 
Copy 3 
Del 3 3 
---const A& a4 = A(4) 
Cstr 4 
---const A& a5 = A(5).thiz() 
Cstr 5 
Del 5 5 
---const A& a6 = constref(A(6)) 
Cstr 6 
Del 6 6 
a1 = { *p=1 , v=1 } 
a2 = { *p=12 , v=12 } 
a3 = { *p=13 , v=13 } 
a4 = { *p=4 , v=4 } 
a5 = { *p=0 , v=5 } 
a6 = { *p=0 , v=6 } 
Del 4 4 
Del 13 13 
Del 12 12 
Del 1 1 

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

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