2013-04-26 19 views
6

Sto tentando di eseguire l'iterazione su un oggetto temporaneo in un intervallo per ciclo. Sembra che l'oggetto venga descritto prima che il ciclo inizi l'esecuzione. È un comportamento conforme allo standard? Sto usando gcc 4.8.std :: shared_ptr non funziona con intervallo per

#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'; 

    } 
} 

Il risultato è il seguente:

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

risposta

13

, il comportamento è conforme.

al comma 6.5.4/1 della C++ 11 standard:

Per una gamma basata for dichiarazione del modulo

for (for-range-declaration : expression) statement 

diamo gamma-init essere equivalente all'espressione circondata da parentesi

(expression) 

e per una gamma basata for dichiarazione della forma

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

lasciare gamma-init essere equivalente al rinforzato-init-list. In ogni caso, una serie-based per dichiarazione equivale a

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

Nel tuo caso, il puntatore condiviso restituito è dereferenziato, e l'oggetto a cui punta è legata al riferimento __range. Tuttavia, il puntatore condiviso stesso non viene copiato, né è associato a un riferimento che ne prolungherebbe la durata. Pertanto, va fuori dal campo di applicazione. Essendo l'ultimo puntatore condiviso che fa riferimento all'oggetto puntato, anche l'oggetto viene distrutto.

cose sarebbero state diverse se fosse tornato l'oggetto Test per valore, invece di restituire un puntatore comune:

Test func() { 
    return Test(); 
} 

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

    } 
} 

In questo modo, il Test temporanea restituita da func() è legata al riferimento __range, e la sua durata è prolungata per corrispondere alla durata del riferimento.

Questo è un live example.

+0

O semplicemente memorizzare shared_ptr come locale: http://ideone.com/U0eC8l –

+0

Oltre alla semplice scelta di mantenere l'istanza 'shared_ptr' in ambito locale, ci sono soluzioni alternative consigliate? – epl

Problemi correlati