2017-12-24 99 views
11

Thực ra lỗi phân đoạn xảy ra trong chương trình khác mà tôi đã cố biên dịch xảy ra do hành vi này.Trình xây dựng ủy nhiệm cho lỗi phân đoạn khi sử dụng trường lớp cho đối số

Câu hỏi của tôi là:

Đây là một lỗi hoặc lỗi của tôi?

tái sản xuất trong bất kỳ cách nào (thậm chí nếu lĩnh vực something là private hay protected) và đây là ví dụ của tôi:

main.cc:

#include <iostream> 
class Test { 
    public: 
     const char* something = "SOMETHING HERE!!!"; 
     Test(const int& number) : Test(something, number) { } 
     // XXX: changed `something` to `_something` to make it different 
     Test(const char* _something, const int& number) { 
      std::cout << _something << std::endl; 
      std::cout << number << std::endl; } 
     ~Test() { } 
}; 

int main(int argc, char* argv[]) { 
    Test te1(345); 
    Test te2("asdasdad", 34523); 
    return 0; 
} 

Và đây là những gì sẽ xảy ra khi biên soạn với:

g++ main.cc -Os -o main 

và chạy với:

./main 

đầu ra là:

[email protected]:~/ $ ./main 
A"�~ <-- this is random 
345 
asdasdad 
34523 

Nhưng khi tôi cho phép tối ưu hóa với -O0 hoặc -O1 hoặc -O2 ... đầu ra chỉ là một dòng sản phẩm mới:

[email protected]:~/ $ ./main 
[email protected]:~/ $ 

G ++ phiên bản:

[email protected]:~/ $ g++ --version 
g++ (Raspbian 6.3.0-18+rpi1) 6.3.0 20170516 
+0

Trong dòng tiếp theo 'const char * something =" SOMETHING HERE !!! ";' bạn có nghĩa là '_something'? Nếu không, thì biến này chưa được đặt. – Mixhab

+0

Mọi thứ đều như tôi đã giải thích trong phần câu hỏi. –

+0

Khá thú vị. – 0x499602D2

Trả lời

20
const char* something = "SOMETHING HERE!!!"; 

Trình khởi tạo mặc định ở bên phải, như tên của nó, chỉ được sử dụng khi bạn không cung cấp bộ khởi tạo rõ ràng trong danh sách bộ khởi tạo của hàm tạo. Hãy xem xét của bạn:

Test(const int& number) : Test(something, number) { } 

Được rồi, chúng tôi đang ủy thác cho một nhà xây dựng khác. Phương thức khởi tạo khác sẽ thực hiện khởi tạo đầy đủ, do đó trình khởi tạo mặc định không được sử dụng. Nhưng ... chúng tôi đang chuyển giá trị uninitialized của something làm thông số.

Test(const char* _something, const int& number) { /* ... */ } 

Uh-oh. Bây giờ chúng tôi đang cố gắng sử dụng giá trị của _something, là bản sao của something, không xác định. Không xác định Hành vi và hỏa hoạn xảy ra sau đó.

Bạn thực sự không nên chuyển giá trị của một thành viên lớp làm tham số cho hàm tạo của nó, trừ khi bạn có nguồn cung cấp gà và trứng vô hạn.


Các hành vi bạn đang tìm kiếm có thể thu được bằng cách đặt giá trị mặc định trong các cuộc gọi đến các nhà xây dựng đại biểu:

Test(const int& number) : Test("SOMETHING HERE!!!", number) { } 

... hoặc giữ nó trong một biến tĩnh chuyên dụng:

static constexpr char *const defaultSomething = "SOMETHING HERE!!!"; 
Test(const int& number) : Test(defaultSomething, number) { } 
+1

Hoặc, một hàm tạo riêng mặc định sẽ cho phép bạn viết, 'Kiểm tra (const char * _something, const int & number): Kiểm tra() {/ * ... * /}' – Davislor

+1

"Bạn thực sự không nên chuyển giá trị của thành viên lớp là tham số cho hàm tạo của nó, trừ khi bạn có nguồn cung cấp vô hạn của gà và trứng chống cháy. " - cũng được thực hiện – sehe

15

Đây là lỗi hoặc lỗi của tôi?

Ồ, đó là lỗi của bạn. Trình khởi tạo thành viên mặc định chỉ được sử dụng để khởi tạo đối tượng thành viên trong một hàm tạo không ủy nhiệm. Theo [class.base.init]/9, tôi nhấn mạnh:

Trong một tổ chức phi ủy constructor, nếu một subobject có khả năng xây dựng được không được chỉ định bởi một mem-initializer-id (kể cả trường hợp không có mem-initializer -list vì các nhà xây dựng không có ctor-initializer), sau đó

  • nếu đơn vị là thành viên dữ liệu không tĩnh mà có một khởi tạo thành viên mặc định và một trong hai [...] các thực thể được khởi tạo từ của nó trình khởi tạo thành viên mặc định như được chỉ định trong [dcl.ini t];

Vì vậy, something không được khởi tạo khi bạn truyền cho nhà xây dựng đích. Chương trình của bạn có hành vi không xác định và bị phá sản.

+6

"Ồ, đó là lỗi của bạn." - lol, không thương xót: D – Quentin

+5

@Quentin - Vâng, OP đã hỏi: P – StoryTeller

+0

Cảm ơn bạn! Tôi chấp nhận câu trả lời của @ Quentin vì hoàn thành hơn. –

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