2015-05-03 14 views
7

C'è un post che si occupa di parentheses or not after the type name quando si utilizza nuovo. Ma che dire di questo:Are() e {} sempre equivalenti se utilizzati per l'inizializzazione con "nuovo"?

Se 'Test' è una classe normale, v'è alcuna differenza tra:

Test* test = new Test(); 
// and 
Test* test = new Test{}; 

Inoltre, supponiamo Test2 ha un costruttore per un argomento di tipo Value, è sempre equivalente a scrivere:

Value v; 
Test2 *test2 = new Test(v); 
// and 
Test2 *test2 = new Test{v}; 
+0

Ho sistemato i problemi terminologici del tuo titolo. –

risposta

9

ci potrebbe essere differenza in contesti che coinvolgono std::initializer_list<>, ad esempio:

Caso 1-() e {}

#include <initializer_list> 
#include <iostream> 
using namespace std; 

struct Test2 { 
    Test2(initializer_list<int> l) {} 
}; 

int main() { 
    Test2* test3 = new Test2(); // compile error: no default ctor 
    Test2* test4 = new Test2{}; // calls initializer_list ctor 
} 

Caso 2: (v) e {v}

struct Value { 
}; 

struct Test3 { 
    Test3(Value v) {} 
    Test3(initializer_list<Value> v) {} 
}; 

int main() { 
    Value v; 
    Test3* test5 = new Test3(v); // calls Test3(Value) 
    Test3* test6 = new Test3{v}; // calls Test3(initializer_list<Value>) 
} 

Come affermato da Meyers e altri c'è anche una differenza enorme quando si utilizza STL:

using Vec = std::vector<int>; 
    Vec* v1 = new Vec(10); // vector of size 10 holding 10 zeroes 
    Vec* v2 = new Vec{10}; // vector of size 1 holding int 10 

e non è limitato a solo

In questo caso non c'è alcuna differenza se (e initializer_list ctor viene ignorato)

#include <initializer_list> 
#include <iostream> 
using namespace std; 

struct Test { 
    Test() {} 
    Test(initializer_list<int> l) {} 
}; 

int main() { 
    Test* test1 = new Test(); // calls default ctor 
    Test* test2 = new Test{}; // same, calls default ctor 
} 

C'è anche una differenza ben nota in questo caso

void f() { 
    Test test{}; 
    Test test2(); 
} 

dove test è oggetto default-inizializzato di tipo Test e test2 è una dichiarazione di funzione.

+0

Questo è stato già affermato nelle risposte alla domanda a cui questo è "un seguito". –

+0

Ho risolto la risposta perché non era corretta –

+0

Accidenti hai ragione - _direct-initialisation_ stesso si definisce _list-initialisation_ se l'inizializzatore fosse una _braced-init-list_. –

4

No!

A nuova-inizializzatore può assumere le seguenti forme:

nuovo-inizializzatore:
      (espressione-list opt)
      rinforzato-init-list

E:

[C++11: 5.3.4/15]: A nuova espressione che crea un oggetto di tipo T inizializza l'oggetto come segue:

  • Se il nuovo inizializzatore è omesso, l'oggetto è predefinito inizializzato (8.5); se non viene eseguita l'inizializzazione, l'oggetto ha un valore indeterminato.
  • In caso contrario, il nuovo inizializzatore viene interpretato in base alle regole di inizializzazione di 8.5 per inizializzazione diretta.

E:

[C++11: 8.5/15]: L'inizializzazione che si verifica nelle forme

T x(a); 
T x{a}; 

così come in new espressioni (5.3.4), static_cast espressioni (5.2.9) , conversioni di tipo notazione funzionale (5.2.3) e inizializzatori di base e membro (12.6.2) sono chiamate inizializzazione diretta .

E:

[C++11: 8.5/16]: La semantica di inizializzatori sono i seguenti. [..]

  • Se l'inizializzatore è una (non tra parentesi) rinforzato-init-list, l'oggetto o il riferimento è list-inizializzato (8.5.4).
  • [..]
  • Se l'inizializzatore è (), l'oggetto è valore-inizializzato.
  • [..]
  • Se l'inizializzazione è diretto inizializzazione, o se non é copia-inizializzazione dove la versione cv-non qualificato del tipo di origine è la stessa classe, o una classe derivata, la classe della destinazione, i costruttori sono considerati. I costruttori applicabili sono enumerati (13.3.1.3) e il migliore viene scelto tramite la risoluzione di sovraccarico (13.3). Il costruttore così selezionato viene chiamato per inizializzare l'oggetto, con l'espressione di inizializzazione o elenco di espressioni come argomento (i). Se nessun costruttore si applica, o la risoluzione di sovraccarico è ambigua, l'inizializzazione è mal formata.
  • [..]

Quindi, vedete, in questo caso (e pochi altri), i due sono definiti per essere entrambi diretta-inizializzazione, ma ulteriori regole significa che a seconda che si usi () o {} e che l'inizializzatore sia vuoto, si possono verificare diversi eventi.

Considerando le regole per lista-inizializzazione, che non dovrà riprodurre qui, i due inizializzatori hanno essenzialmente lo stesso effetto se T non ha un costruttore di prendere un std::initializer_list<>.

+1

... e * se * 'T' non è un aggregato. –

4

La risposta generale è no. L'uso di una lista di init rinforzata come l'inizializzatore proverà per la prima volta a risolvere il costruttore che prende uno std::initializer_list. A titolo di esempio:

#include <iostream> 
#include <vector> 
int main() { 
    auto p = new std::vector<int>{1}; 
    auto q = new std::vector<int>(1); 
    std::cout << p->at(0) << '\n'; 
    std::cout << q->at(0) << '\n'; 
} 

Nota la semantica di lista-inizializzazione (citato da cppreference):

  • Tutti i costruttori che si std :: initializer_list come unico argomento, o come il primo argomento se gli argomenti rimanenti hanno valori predefiniti , vengono esaminati e confrontati dalla risoluzione di sovraccarico rispetto a un singolo argomento di tipo std :: initializer_list
  • Se la fase precedente non produce uce una corrispondenza, tutti i costruttori di T partecipano alla risoluzione di sovraccarico rispetto all'insieme di argomenti che è costituito dagli elementi dell'elenco di parentesi rinforzati, con la restrizione che sono consentite solo conversioni non restrittive. Se questa fase produce un costruttore esplicito come la migliore corrispondenza per una copia-list-inizializzazione , la compilazione fallisce (si noti, in modo semplice copia-inizializzazione, costruttori espliciti non sono considerati a tutti)
+0

penso che siano diversi anche nel primo caso – sp2danny

+0

@ sp2danny Credo che tu abbia ragione. – Lingxi

+0

@ sp2danny La semantica dell'inizializzazione delle liste è davvero complicata. Diverse versioni di C++ hanno anche dichiarazioni diverse a riguardo. Ad ogni modo, decido di lasciare la risposta come è ora, poiché è la parte più rilevante nella programmazione quotidiana, con cui le persone dovrebbero familiarizzarsi. Ma anche una modifica a questa risposta per renderla più accurata è gradita. – Lingxi

Problemi correlati