2015-05-03 14 views
7

有一個帖子,當使用新的處理parentheses or not after the type name。但是這個東西:當用「new」初始化時,Are和{}總是等價的嗎?

如果「測試」是一個普通的類,有沒有什麼區別:

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

此外,假設Test2已經爲Value類型的參數的構造,是它總是等同於寫:

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

我固定您的標題的術語問題。 –

回答

9

有可能在環境中的差異涉及std::initializer_list<>,如:

案例1 - (){}

#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 
} 

案例2:(v){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>) 
} 

正如邁爾斯陳述,並使用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 

並不限於std::vector只有

在這種情況下沒有差別,但(和initializer_list構造函數被忽略)

#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 
} 

也有在這種情況下,一個衆所周知的差異

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

其中test是類型的默認初始化對象Testtest2是一個函數聲明。

+0

這個問題的答案已經在這個問題的答案中說明了,這是「後續」。 –

+0

我修正了答案,因爲它是不正確的 –

+0

該死的你是對的 - 如果初始化程序是_braced-init-list_,_direct-initialisation_本身就按照_list-initialisation_。 –

4

不!

新初始化可採取以下形式:

新初始化
      (表達式列表選擇)
      支撐-INIT列表

和:

  • 如果

    [C++11: 5.3.4/15]:新表達創建T類型的對象如下初始化該對象新初始化程序被省略,對象是默認初始化(8.5);如果沒有執行初始化,則該對象具有不確定的值。

  • 否則,新初始化程序根據初始化規則8.5解釋爲直接初始化

和:

[C++11: 8.5/15]:發生在形式初始化

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

以及在new表達式(5.3.4),static_cast式(5.2.9) ,功能符號類型轉換(5.2.3)以及基本和成員初始值設定項(12.6.2)被稱爲直接初始化

和:

[C++11: 8.5/16]:初始化的語義如下。 [..]

  • 如果初始化爲(非括號)支撐-INIT列表,對象或參考是列表初始化(8.5.4)。
  • [..]
  • 如果初始化是(),對象是值初始化
  • [..]
  • 如果初始化直接初始化,或者如果它是複製初始化其中源類型的CV-不合格的版本是相同的類,或者派生類的,類的目的地,建設者被考慮。列舉了適用的構造函數(13.3.1.3),並且通過重載決議(13.3)選擇了最佳的構造函數 。調用如此選擇的構造函數來初始化對象,初始化器表達式或表達式列表作爲它的參數。如果不應用構造函數,或者重載解析模糊不清,則初始化不合格。
  • [..]

所以,你看,在這種情況下(和其他一些),這兩個被定義爲同時爲直接初始化,但進一步的規則意味着根據您使用的是()還是{}以及初始化程序是否爲空,可能會發生不同的事情。

考慮列表初始化的規則,我不會在這裏重現,兩個initialisers具有基本相同的效果如果T沒有構造服用std::initializer_list<>

+1

... * 'T'不是一個聚合。 –

4

一般的答案是否定的。使用braced-init-list作爲初始化器將首先嚐試解析構造函數,該構造函數採用std::initializer_list。作爲一個例證:

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

注意列表初始化的(從cppreference的引用)的語義:

  • 所有構造函數採取的std :: initializer_list作爲唯一的參數,或者作爲第一個參數如果其餘參數有 默認值,則檢查並通過重載分辨率 與std :: initializer_list的單個參數進行匹配:
  • 如果前一階段不生成如果匹配,則T的所有構造函數都參與重載解析,這些參數是由加載初始化列表的元素組成的 ,限制 僅允許非縮小轉換。如果這個階段 產生一個明確的構造函數的 副本列表初始化的最佳匹配,編譯失敗(注,在簡單 複製初始化,顯式的構造都沒有考慮)
+0

我認爲他們在第一種情況下也是不同的 – sp2danny

+0

@ sp2danny我想你是對的。 – Lingxi

+0

@ sp2danny列表初始化的語義非常複雜。不同版本的C++也有不同的陳述。無論如何,我決定離開現在的答案,因爲它是日常編程中最相關的部分,人們應該熟悉這一部分。但是,編輯這個答案以使其更加準確也是受歡迎的。 – Lingxi

相關問題