2013-04-26 8 views
6

Próbuję iterować nad tymczasowym obiektem w zakresie pętli. Wygląda na to, że obiekt zostanie zniekształcony przed rozpoczęciem wykonywania pętli. Czy jest to zachowanie zgodne z normą? Używam gcc 4.8.std :: shared_ptr nie działa z zakresem dla

#include <iostream> 
#include <vector> 
#include <memory> 

struct Test: std::vector<int> { 
    Test(): std::vector<int>{1,2,3} { 
    std::cout << __PRETTY_FUNCTION__ << '\n'; 
    } 

    ~Test() { 
    std::cout << __PRETTY_FUNCTION__ << '\n'; 
    } 
}; 

std::shared_ptr<Test> func() { 
    return std::shared_ptr<Test>(new Test); 
} 

int main() { 
    for (const auto &obj: *func()) { 
    std::cout << obj << '\n'; 

    } 
} 

Wynik jest następujący:

Test::Test() 
Test::~Test() 
21770300 
0 
33 
0 
0 
0 
3 

Odpowiedz

13

Tak, zachowanie jest zgodny.

zgodnie z pkt 6.5.4/1 o C++ 11 Standard:

dla zakresu opartych for zestawienia postaci

for (for-range-declaration : expression) statement 

niech zakres-startowych za równoważne do wyrażenia otoczonego nawiasami:

(expression) 

i dla zakresu for zestawienie postaci

for (for-range-declaration : braced-init-list) statement 

niech zakres-startowych być równoważna usztywnione-init-listy. W każdym przypadku, zakres oparty na rachunku jest równoznaczne

{ 
    auto && __range = range-init; 
    for (auto __begin = begin-expr, 
     __end = end-expr; 
     __begin != __end; 
     ++__begin) { 
     for-range-declaration = *__begin; 
     statement 
    } 
} 

w Twoim przypadku, zwracany jest wspólny wskaźnik dereferencjonowane, a obiekt to wskazuje jest związany z odniesieniem __range. Jednak sam udostępniony wskaźnik nie jest kopiowany, ani nie jest powiązany z odwołaniem, które przedłużyłoby jego żywotność. Dlatego wykracza poza zakres. Będąc ostatnim współdzielonym wskaźnikiem odwołującym się do spiczastego obiektu, obiekt jest również niszczony.

miejsca byłaby inna, jeśli wrócił swój obiekt Test według wartości, raczej niż powrót wspólny wskaźnik:

Test func() { 
    return Test(); 
} 

int main() { 
    for (const auto &obj: func()) { 
    std::cout << obj << '\n'; 

    } 
} 

ten sposób Test tymczasowy zwrócony przez func() jest związany z odniesieniem __range i jego żywotność jest przedłużona, aby dopasować czas życia referencji.

Oto live example.

+0

Lub po prostu przechowuj shared_ptr jako lokalny: http://ideone.com/U0eC8l –

+0

Czy oprócz zwykłego wyboru posiadania instancji 'shared_ptr' w zasięgu lokalnym, czy są jakieś zalecane obejścia? – epl