2013-04-24 40 views
60

Tôi đã thử nghiệm ở đây, nhưng đầu ra là một vòng lặp không có kết thúc, tôi không biết tại sao.Vòng lặp vô hạn trong hàm tạo mà không cần hoặc trong khi

Thực ra, tôi đang làm một thử nghiệm khác, nhưng khi tôi viết bài này, tôi không hiểu cách vòng lặp xảy ra. Nó là đầu ra "ABC" nhiều lần.

#include <map> 
#include <string> 
#include <iostream> 

class test 
{ 
public: 
    std::map <int, int> _b; 
    test(); 
    test (std::map<int, int> & im); 
    ~test(); 
    }; 

test::test() 
{ 
    std::cout<<"abc"; 
    _b.clear(); 
    _b[1]=1; 
    test(_b); 
} 

test::test(std::map <int, int>& im) 
{ 
    std::cout<<im[1]; 
} 

test::~test() {}; 

int main() 
{ 
    test a; 
} 
+1

Đó là đệ quy do 'test (_b);' nhưng tôi không chắc chắn tại sao. – Roddy

+0

@ Roddy- Tôi chỉ tìm ra; xem câu trả lời của tôi để biết chi tiết. – templatetypedef

+1

Làm sạch phiên bản với những thứ không quan trọng bị loại bỏ: http://ideone.com/z0yc7Q – Yakk

Trả lời

94

Vấn đề ở đây là trình biên dịch dịch

test(_b); 

Không như mã tạo một đối tượng tạm thời loại test đi qua trong tham số _b, nhưng như một khai báo biến cho một biến có tên _b loại test, sử dụng hàm tạo mặc định. Do đó, những gì trông giống như một đoạn mã tạo đối tượng test tạm thời bằng cách sử dụng hàm tạo thứ hai, thay vào đó đệ quy tạo đối tượng mới kiểu test và gọi hàm khởi tạo một lần khác.

Để sửa lỗi này, bạn có thể cho biến một tên rõ ràng, chẳng hạn như

test t(_b); 

này chỉ có thể được hiểu như là một biến kiểu test tên t, khởi tạo bằng cách sử dụng constructor thứ hai.

Tôi có chưa bao giờ thấy điều này trước đây và tôi đã lập trình bằng C++ trong nhiều năm. Cảm ơn bạn đã hiển thị cho tôi một trường hợp khác của ngôn ngữ góc là!

Để có giải thích chính thức: Theo thông số ISO C++ 03, § 6.8:

Có sự mơ hồ trong ngữ pháp liên quan đến biểu thức và khai báo: Biểu thức tuyên bố bằng chuyển đổi loại rõ ràng theo chức năng (5.2.3) là biểu thức con ngoài cùng bên trái có thể không phân biệt được các declarator đầu tiên bắt đầu với một (. Trong những trường hợp báo cáo kết quả là một bản tuyên bố.

(nhấn mạnh của tôi). Nói cách khác, bất cứ lúc nào C++ có thể giải thích một tuyên bố như hoặc là một biểu thức (đối tượng tạm thời dàn diễn viên) hoặc như một khai báo (của một biến), nó sẽ chọn khai báo. C++ spec rõ ràng cung cấp cho

T (a);

Ví dụ về tuyên bố, không phải là một diễn viên của a đối với loại nội dung T.

Đây là sốcủa C++ - thay vào đó, biểu thức giống như biểu thức được hiểu là khai báo. Tôi đã nhìn thấy MVP trước đây, nhưng tôi chưa bao giờ thấy nó trong bối cảnh này.

Hy vọng điều này sẽ hữu ích!

+1

Cảm ơn, điều này thật đáng ngạc nhiên đối với Google. – Antimony

+0

Câu trả lời hay! Bất kỳ tài liệu tham khảo đặc điểm kỹ thuật có sẵn để chứng minh/disprove rằng trình biên dịch là giải thích điều này một cách chính xác? FWIW, codepad.org trưng bày cùng một hành vi – Tom

+0

Ah, tôi đã tìm thấy một lời giải thích. Nó được gọi là "Vexing Parse". Nhân tiện, trong C++ 11 bạn có thể sửa lỗi này bằng cách thay đổi nó thành 'test {_b}'. (Sử dụng dấu ngoặc đơn thay vì dấu ngoặc đơn) http://en.wikipedia.org/wiki/Most_vexing_parse – Antimony

0

vấn đề được từ constructor bạn một lần nữa kêu gọi các thử nghiệm contructor (_b)

thử nghiệm :: test() {std :: cout < < "abc"; _ b.clear(); _b [1] = 1; kiểm tra (_b);}

đây là những gì xảy ra

mọi lúc bạn gọi kiểm tra (_b) nó cuộc gọi đầu tiên mặc định constructor thử nghiệm :: thử nghiệm và nó trong biến cuộc gọi các thử nghiệm (_b) và vòng lặp đi và về cho đến khi tràn ngăn xếp.

loại bỏ các thử nghiệm (_b) từ các nhà xây dựng mặc định

+0

Tại sao điều này gọi hàm tạo mặc định? Tôi figured này sẽ gọi constructor chuyển đổi tiềm ẩn 'test :: test (std :: map &)', kể từ khi nó rõ ràng vượt qua trong '_b'. – templatetypedef

+0

Tại sao nó gọi hàm tạo mặc định? C++ không xây dựng chuỗi. – Antimony

+0

Trong C++ bạn không nên gọi một hàm tạo khác. Điều này khác với Java chẳng hạn. – OlivierD

0

Tôi không quen thuộc với đặc thù của các tiêu chuẩn, nhưng nó có thể là gọi một constructor trong một constructor là undefined. Như vậy nó có thể là trình biên dịch phụ thuộc. Trong trường hợp cụ thể này nó gây ra sự đệ quy vô hạn của hàm tạo mặc định của bạn mà không bao giờ gọi hàm tạo của bạn với đối số bản đồ.

C++ Câu hỏi thường gặp 10.3 có ví dụ về hàm tạo có hai tham số. Nếu bạn thêm một tham số int vào hàm tạo thứ hai của bạn chẳng hạn như test(map, int), nó thể hiện một hành vi hơi bình thường.

Để có biểu mẫu tốt, tôi chỉ cần thay đổi test::test(std::map <int, int>& im) cho test::testInit(std::map <int, int>& im)test(_b) đến testInit(_b).

+0

Nó gọi một hàm tạo khác, nhưng nó không giống như hàm tạo như trước. Tôi không hiểu tại sao điều đó sẽ gây ra sự đệ quy vô hạn được trưng bày ở đây. – templatetypedef

0

Tôi khá chắc chắn rằng bạn không thực sự là "gọi hàm tạo" vì chúng không thể gọi trực tiếp IIRC. Pháp lý đã phải làm với các nhà thầu không phải là các chức năng được đặt tên - Tôi không có bản sao của tiêu chuẩn tiện dụng hoặc tôi có thể báo giá nó. Tôi tin rằng những gì bạn đang làm với test(_b) đang tạo một tên miền tạm thời chưa được đặt tên gọi hàm dựng mặc định.

+0

Nó không tạo ra một tạm thời chưa được đặt tên và gọi hàm tạo mặc định; thay vào đó, nó tạo ra một biến có tên '_b' và gọi hàm khởi tạo mặc định trên nó. Xem câu trả lời của tôi để biết thêm chi tiết. – templatetypedef

+0

Cảm ơn. Tôi nhớ những gì nó đã làm không phải là lý do chính xác. Tôi đã quên làm thế nào xoắn các quy tắc khai báo C/C++ thực sự là. –

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