2012-08-05 19 views
14

Il costruttore std :: shared_ptr non si comporta come mi aspettavo:std :: shared_ptr e inizializzazione liste

#include <iostream> 
#include <vector> 

void func(std::vector<std::string> strings) 
{ 
    for (auto const& string : strings) 
    { 
     std::cout << string << '\n'; 
    } 
} 

struct Func 
{ 
    Func(std::vector<std::string> strings) 
    { 
     for (auto& string : strings) 
     { 
      std::cout << string << '\n'; 
     } 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 

    func({"foo", "bar", "baz"}); 
    Func({"foo", "bar", "baz"}); 
    //auto ptr = std::make_shared<Func>({"foo", "bar", "baz"}); // won't compile. 
    //auto ptr = std::make_shared<Func>{"foo", "bar", "baz"}; // nor this. 
    return 0; 
} 

sto facendo qualcosa di sbagliato o è il compilatore? Il compilatore è:

$ clang ++ --version di Apple clang versione 4.0 (tag/Apple/clang-421.0.57) (sulla base di LLVM 3.1svn)

edit: shared_ptr invece di make_shared.

Ecco l'errore:

make -k 
clang++ -std=c++11 -stdlib=libc++ main.cc -o main 
main.cc:28:18: error: no matching function for call to 'make_shared' 
     auto ptr = std::make_shared<Func>({"foo", "bar", "baz"}); 
       ^~~~~~~~~~~~~~~~~~~~~~ 
/usr/bin/../lib/c++/v1/memory:4621:1: note: candidate function not viable: 
    requires 0 arguments, but 1 was provided 
make_shared(_Args&& ...__args) 
^ 
1 error generated. 

risposta

21

Prova questo:

auto ptr = std::make_shared<Func>(std::initializer_list<std::string>{"foo", "bar", "baz"}); 

Clang non è disposto a dedurre il tipo di {"foo", "bar", "baz"}. Al momento non sono sicuro se questo è il modo in cui la lingua dovrebbe funzionare, o se stiamo guardando un bug del compilatore.

+5

Ultimo ho sentito, è noto che l'inoltro perfetto non è in realtà perfetto quando si tratta di elenchi di inizializzatori. – Puppy

+2

{"foo", "bar", "baz"} non è un'espressione e come tale non ha tipo (tranne se usato con auto) .. Anche se sarebbe bello – Cubbi

3

È necessario utilizzare make_shared se si desidera creare un nuovo oggetto, costruito da tali argomenti, puntato da un shared_ptr. shared_ptr<T> è come un puntatore a T - deve essere costruito con un puntatore a T, non uno T.

Modifica: l'inoltro perfetto non è affatto perfetto quando sono coinvolti gli elenchi di inizializzatori (che è l'aspirazione). Non è un bug nel compilatore. Dovrai creare manualmente un valore di tipo Func.

+0

Siamo spiacenti, il problema è stato con make_shared. L'ho cambiato in shared_ptr mentre fingo. – dpj

4

Il costruttore di shared_ptr<T> utilizza un puntatore di tipo T* come argomento, presupposto per indicare una risorsa allocata dinamicamente (o almeno qualcosa che può essere liberata dal deleter). D'altra parte, make_shared esegue la costruzione per te e prende direttamente gli argomenti del costruttore.

Quindi, o si dicono questo:

std::shared_ptr<Foo> p(new Foo('a', true, Blue)); 

Oppure, molto meglio e in modo più efficiente:

auto p = std::make_shared<Foo>('a', true, Blue); 

Quest'ultima forma si prende cura della dotazione e delle costruzioni per voi, e nel processo crea un'implementazione più efficiente.

Si potrebbe anche dire make_shared<Foo>(Foo('a', true, Blue)), ma ciò creerebbe solo una copia non necessaria (che può essere eliminata) e, soprattutto, crea una ridondanza inutile. [Modifica] per inizializzare il vostro vettore, questo può essere il metodo migliore:

auto p = std::make_shared<Func>(std::vector<std::string>({"a", "b", "c"})); 

Il punto importante è, però, che make_sharedesegue l'allocazione dinamica per voi, mentre il costruttore condiviso-PTR fa non e invece assume la proprietà.

+0

scusa. Voi ragazzi siete così veloci!Il problema era con make_shared. – dpj

+0

"* ma ciò creerebbe solo una copia non necessaria *" Una mossa non necessaria. – ildjarn

+0

@ildjarn: Beh, tutto dipende, vero? Ad ogni modo, "move" è solo una copia ottimizzata :-) –

Problemi correlati