2014-07-13 28 views
7

Dự thảo cuốn sách Effective C++11 Scott Meyers nói:Sự khác nhau giữa `Object obj (args ...)` và `Object obj {args ...}` là gì?

Phân biệt() và {} khi tạo các đối tượng

sự khác biệt giữa Object obj(args...)Object obj{args...} là gì? và tại sao Scott nói vậy.

Cập nhật:

Câu hỏi How to use C++11 uniform initialization syntax? yêu cầu như thế nào, và câu hỏi này yêu cầu TẠI SAO.

Update2:

tôi thấy đường dẫn sau là hữu ích và hoàn toàn trả lời câu hỏi này:

https://softwareengineering.stackexchange.com/questions/133688/is-c11-uniform-initialization-a-replacement-for-the-old-style-syntax

+0

thể trùng lặp của [Làm thế nào để sử dụng C++ 11 cú pháp khởi tạo thống nhất?] (Http://stackoverflow.com/questions/7612075/how-to-use-c11-uniform-initialization-syntax) –

+0

@MattMcNabb, câu hỏi đó yêu cầu CÁCH, câu hỏi này yêu cầu TẠI SAO. – xmllmx

+5

Câu hỏi này không hỏi "TẠI SAO", và câu hỏi khác bao gồm khởi tạo thống nhất nào. –

Trả lời

5

sự khác biệt giữa Object obj(args...)Object obj{args...} là gì?

Đầu tiên là trực khởi trong khi thứ hai là trực tiếp-list-khởi. Đây được nhắc đến trong hai phần khác nhau:

§8.5/16 [dcl.init]

Việc khởi xảy ra dưới các hình thức

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

cũng như trong new biểu thức (5.3.4), static_cast biểu thức (5.2.9), chuyển đổi loại ký hiệu chức năng (5.2.3) và bộ khởi tạo cơ sở và thành viên (12.6.2) được gọi là khởi tạo trực tiếp.

§8.5.4/1 [dcl.init.list]

List-khởi là khởi tạo của một đối tượng hoặc tham khảo từ một chuẩn bị tinh thần-init-list. Trình khởi tạo như vậy được gọi là danh sách khởi tạo và các mệnh đề khởi tạo được phân cách bằng dấu phẩy của danh sách được gọi là các phần tử của danh sách bộ khởi tạo. Danh sách trình khởi tạo có thể trống. Việc khởi tạo danh sách có thể xảy ra trong bối cảnh khởi tạo trực tiếp hoặc khởi tạo sao chép; khởi tạo danh sách trong ngữ cảnh khởi tạo trực tiếp được gọi là khởi tạo danh sách trực tiếp và khởi tạo danh sách trong ngữ cảnh khởi tạo sao chép được gọi là sao chép danh sách bản sao.


Có một vài khác biệt giữa hai:

  • Nếu loại được xây dựng có một constructor đó có một đối initializer_list, trực tiếp-list-khởi sẽ luôn ủng hộ mà constructor. Các nhà xây dựng khác sẽ chỉ được xem xét nếu nhà xây dựng initializer_list không khả thi. §13.3.1.7/1 [over.match.list]

  • trực tiếp-list-khởi không cho phép thu hẹp chuyển đổi trong danh sách đối số. §8.5.4/3 [dcl.init.list]

  • Nếu loại được khởi tạo là một tổng hợp, trực tiếp-list-khởi sẽ thực hiện tổng khởi tạo. §8.5.4/3 [dcl.init.list]

  • Trình tự đánh giá của các yếu tố của một chuẩn bị tinh thần-init-list là từ trái sang phải. §8.5.4/4 [dcl.init.list]

  • Bạn có thể tránh được những phân tích cú pháp gây nhiều tranh cãi nhất bằng cách sử dụng trực tiếp-list-khởi

 

struct foo{}; 
    struct bar 
    {  
    bar(foo const&) {} 
    }; 

    bar b1(foo()); // most vexing parse 
    bar b2(foo{}); // all 3 of the following construct objects of type bar 
    bar b3{foo()}; 
    bar b4{foo{}}; 
1

là gì sự khác biệt giữa Object obj (args ...) và đối tượng obj {args ...}? và tại sao Scott nói vậy.

Sự khác biệt là trong trường hợp trước, thứ tự đánh giá đối số không được xác định (nghĩa là không xác định) nhưng trong trường hợp thứ hai, thứ tự từ trái sang phải (nghĩa là chúng xuất hiện).

Các văn bản sau đây từ $ 5.2.2/8 [expr.call] (n3690) giao dịch với Object(args...) dạng:

Các đánh giá của biểu thức postfix và của các đối số đều unsequenced liên quan đến một khác. Tất cả các tác dụng phụ của việc đánh giá đối số được giải trình tự trước khi hàm được nhập (xem 1.9).

Và văn bản từ $ 8.5.4/4 [dcl.init.list] (n3690) giao dịch với Object{args...} dạng:

Trong initializer-list của một chuẩn bị tinh thần-init-danh sách, điều khoản khởi tạo, bao gồm bất kỳ kết quả nào từ mở rộng gói (14.5.3), là được đánh giá theo thứ tự xuất hiện. Tức là, mọi tính toán giá trị và mệnh đề phụ được kết hợp với mệnh đề khởi tạo cho trước được tính toán trước mỗi lần tính toán giá trị và e ff ect liên kết với bất kỳ mệnh đề khởi tạo nào theo sau trong danh sách được phân tách bằng dấu phẩy. [Lưu ý: các yêu cầu đặt hàng đánh giá bất kể ngữ nghĩa của việc khởi tạo ; ví dụ, nó áp dụng khi các phần tử của danh sách khởi tạo được hiểu là đối số của lệnh gọi hàm dựng, mặc dù thông thường không có ràng buộc trình tự trên các đối số của cuộc gọi.- cuối note]

Vâng điều đó có nghĩa này:

int f() { static int i = 10; return ++i; } //increment the static int! 

Object obj(f(), f()); //is it obj(11,12) or obj(12,11)? Unspecified. 

Object obj{f(), f()}; //it is obj(11,12). Guaranteed. 

Lưu ý rằng GCC (4.7.0 and 4.7.2) have a bug because of which {} form doesn't work the way it should. Tôi không chắc chắn nếu nó được cố định trong phiên bản hiện tại.

Hy vọng điều đó sẽ hữu ích.

2

Hành vi của Object obj(args...)Object{args...} tùy thuộc vào các nhà thầu được xác định trong Object.

Lấy ví dụ sau đây:

#include <iostream> 
#include <initializer_list> 

struct A 
{ 
    A(int a, int b) {std::cout << "Came to A::A()\n";} 
}; 

struct B 
{ 
    B(int a, int b) {std::cout << "Came to B::B(int, int)\n";} 
    B(std::initializer_list<int> in) {std::cout << "Came to B::B(std::initializer_list<int>)\n";} 
}; 

int main() 
{ 
    A a1(10, 20); // Resolves to A(int, int) 
    A a2{10, 20}; // Resolves to A(int, int) 
    A a3{30};  // Does not resolve to anything. It's a compiler error. 

    B b1(10, 20); // Resolves to B(int, int) 
    B b2{10, 20}; // Resolves to B(std::initializer_list<int>) 
    B b3{30};  // Resolves to B(std::initializer_list<int>) 

} 
1

Sự khác nhau giữa Object obj (args ...) và Object obj {args ...} là gì?

{args ...} sẽ thích một hàm tạo với một initializer_list hơn các ứng cử viên pháp lý khác.

std::vector<int> v(10); // vector of size 10 
std::vector<int> v{10}; // vector initialized with a single element, (int) 10 

Mặt khác, bạn từ bỏ thu hẹp tiềm ẩn.

std::vector<int> v(10.5); // vector of size 10 
std::vector<int> v{10.5}; // illegal - no compile 
std::vector<float> v{10.5}; // vector initialized with a single element, (float) 10.5 
Các vấn đề liên quan