33

xem xét:Các hàm gọi trong danh sách khởi tạo của trình xây dựng có được sắp xếp không?

int f() { 
    static int i = 0; 
    return i++; 
} 

struct Test { 
    int a, b; 
    Test() : a(f()), b(f()) {} 
}; 

Test t; 

Tôi biết rằng a được khởi tạo trước khi b do trình tự của việc kê khai trong struct.

Tôi cũng biết rằng hai cuộc gọi đến f trong g(f(), f()) không được kết thúc.

Vì vậy, tôi tự hỏi nếu nó được đảm bảo rằng t.a == 0t.b == 1?

+0

@ FrançoisAndrieux Tôi không cho rằng đó là bản sao. Câu hỏi này là cụ thể đối phó với thứ tự của các cuộc gọi chức năng trong danh sách khởi tạo thành viên, đó không phải là những gì mà câu hỏi đề cập đến. – Xirema

+0

@ FrançoisAndrieux - đừng nghĩ đó là sự lừa đảo. OP biết rằng 'a' được khởi tạo trước' b'. Nhưng đang hỏi liệu hai lệnh gọi tới 'f()' có được sắp xếp theo trình tự hay không. Có thể là 'f()' được gọi hai lần trước khi 'a' hoặc' b' được khởi tạo. –

+1

Tôi cần xác minh nhưng tôi tin là vậy. –

Trả lời

30

Vì vậy, tôi tự hỏi nếu nó được đảm bảo rằng t.a == 0t.b == 1?

này sẽ luôn luôn đúng chừng nào a đến trước b trong khai báo lớp và không có gì khác gọi f() giữa khởi của ab. Các thành viên lớp được khởi tạo theo thứ tự chúng được khai báo trong lớp. [Class.base.init]/11:

Trong một constructor không ủy thác, tiền thu được khởi tạo theo trình tự sau: [...]

  • Sau đó, không tĩnh thành viên dữ liệu được khởi tạo theo thứ tự chúng được khai báo trong định nghĩa lớp (một lần nữa bất chấp thứ tự của bộ khởi tạo mem).

Vì vậy, kể từ a đến trước b sau đó khi các nhà xây dựng khởi a nó sẽ gọi f() lần đầu tiên và sau đó nó sẽ gọi nó là một lần thứ hai khi nó khởi b.

Chúng tôi cũng biết có một điểm chuỗi giữa initializer viên vì [class.base.init]/7:

[...] Việc khởi thực hiện bởi mỗi mem-initializer tạo thành một toàn thể hiện . Bất kỳ biểu thức nào trong bộ khởi tạo mem được đánh giá là một phần của biểu thức đầy đủ thực hiện khởi tạo.

cho chúng ta biết mỗi initializer là một biểu hiện đầy đủ và mỗi biểu hiện đầy đủ trình tự: [intro.execution]/14

Mỗi giá trị tính toán và phụ ảnh hưởng kết hợp với một thể hiện đầy đủ trình tự trước mỗi tính toán giá trị và tác dụng phụ liên quan đến biểu thức đầy đủ tiếp theo được đánh giá.

+0

Câu trả lời tuyệt vời! Nhưng tất nhiên, chỉ khi 'f()' được gọi là hư không khác và đặc biệt là không có khởi tạo tĩnh khác :-) – Christophe

+0

@Christophe Cảm ơn. Tôi cũng thêm chút ít miếng ngon. – NathanOliver

6

Tôi biết rằng a được khởi tạo trước b do thứ tự khai báo của chúng trong cấu trúc.

Đó là sự thật.

Việc giải thích ràng buộc của tôi là a không thể được khởi tạo trước b trừ khi việc đánh giá biểu thức khởi tạo hoàn tất trước khi b được khởi tạo.

Tôi không thấy bất kỳ điều gì trong tiêu chuẩn nói về trình tự việc đánh giá các biểu thức được sử dụng để khởi tạo thành viên không tĩnh. Tuy nhiên, tôi thấy ví dụ sau trong tiêu chuẩn C++ 11 (12.6.2/12):

Tên trong danh sách biểu hiện hoặc braced-init-list của bộ khởi tạo mem được đánh giá trong phạm vi của hàm tạo mà bộ khởi tạo mem được chỉ định. [Ví dụ:

class X { 
    int a; 
    int b; 
    int i; 
    int j; 
    public: 
    const int& r; 
    X(int i): r(a), b(i), i(i), j(this->i) { } 
}; 

Điều đó sẽ không có giá trị trừ khi việc thẩm định this->i được lập trình tự sau i được khởi tạo.

Các vấn đề liên quan