2012-04-25 30 views
7

Tôi đã thử nghiệm đoạn mã sau:Trong đó trường hợp là các nhà xây dựng bản sao gọi là, nếu một container được sao chép

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor" << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor" << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    std::vector<foo> b(4, foo(4)); 
    //std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 
    return 0; 
} 

tôi nhận được

parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    parameterised constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 
    a = b 
    copy constructor 
    copy constructor 
    copy constructor 
    copy constructor 

Tuy nhiên, nếu tôi thay std::vector<foo> b(4, foo(4)); bởi std::vector<foo> b(3, foo(4)); constructor sao chép không được gọi bởi a = b và đầu ra là

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 

Tại sao trong trường hợp này, trình tạo bản sao không được gọi?

Tôi đang sử dụng g ++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

Điều này thực sự lạ ... Nó thậm chí có thể tái sản xuất tại ideone ... – RedX

+0

Sooo cool. :) Tôi cũng sao chép điều đó, mặc dù tôi không tin điều đó. –

+0

có thể trình biên dịch đơn giản di chuyển b đến a vì b không được sử dụng sau khi gán? Bạn đã thử làm gì đó với b sau a = b (in ấn, vv)? – user396672

Trả lời

12

Trong trường hợp đầu tiên, a nhu cầu phát triển khi bạn gán cho nó, có nghĩa là tất cả các yếu tố của nó phải được phân bổ lại (và do đó bị phá hủy và xây dựng).

Trong trường hợp thứ hai, a không cần phát triển, do đó toán tử gán được sử dụng.

Xem http://ideone.com/atPt9; thêm một toán tử gán bản sao quá tải để in một thông báo, chúng tôi nhận được thông tin sau cho ví dụ thứ hai:

parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
parameterised constructor 
copy constructor 
copy constructor 
copy constructor 
a = b 
copy assignment 
copy assignment 
copy assignment 
+0

Tuy nhiên, như chúng ta biết, cấu trúc 'vector' dự trữ một số phần tử dự phòng, để đảm bảo tốc độ không đổi được phân bổ cho các hoạt động của nó. Tại sao sau đó sao chép constructor được sử dụng mỗi lần nevermind các kích thước ban đầu của a và b? –

+0

@Boris: nó không được sử dụng không bao giờ có kích thước ban đầu. Toàn bộ điểm của câu hỏi là với một cặp kích thước ban đầu nó được sử dụng, và với một cặp khác thì không. Hãy thử 'std :: vector a (3, foo (3)); std :: vector b (4, foo (4)); a.reserve (4); a = b; '. Giả sử lời giải thích của Oli là chính xác, tôi nghĩ rằng nên sao chép xây dựng 3 lần trong thời gian dự trữ và sau đó sao chép-xây dựng một lần trong nhiệm vụ (và sao chép-giao ba lần). Nếu bạn đang ở trên C++ 11, thì thông thường 'dự trữ' có thể di chuyển thay vì sao chép, nhưng IIRC là một hàm tạo do người dùng định nghĩa sẽ ngăn cản hàm khởi tạo mặc định. –

+0

@BorisStrandjev: Sử dụng hàm tạo 'vector (count, T)', công suất được đặt thành 'count' (không chắc chắn nếu đó là bắt buộc theo tiêu chuẩn hoặc triển khai cụ thể). Xem ví dụ http://ideone.com/jngf9. –

3

Đang sử dụng toán tử gán.

#include <iostream> 
#include <vector> 

class foo { 
public: 
    int m_data; 
    foo(int data) : m_data(data) { 
     std::cout << "parameterised constructor " << m_data << std::endl; 
    } 
    foo(const foo &other) : m_data(other.m_data) { 
     std::cout << "copy constructor " << m_data << " " << other.m_data << std::endl; 
    } 

    foo& operator= (const foo& other){ 
     std::cout << "assignment operator " << m_data << " " << other.m_data << std::endl; 
    } 
}; 

main (int argc, char *argv[]) { 
    std::vector<foo> a(3, foo(3)); 
    //std::vector<foo> b(4, foo(4)); 
    std::vector<foo> b(3, foo(4)); 
    std::cout << "a = b" << std::endl; 
    a = b; 

    for(std::vector<foo>::const_iterator it = a.begin(); it != a.end(); ++it){ 
     std::cout << "a " << it->m_data << std::endl; 
    } 
    for(std::vector<foo>::const_iterator it = b.begin(); it != b.end(); ++it){ 
     std::cout << "b " << it->m_data << std::endl; 
    } 
    return 0; 
} 
parameterised constructor 3 
copy constructor 3 3 
copy constructor 3 3 
copy constructor 3 3 
parameterised constructor 4 
copy constructor 4 4 
copy constructor 4 4 
copy constructor 4 4 
a = b 
assignment operator 3 4 
assignment operator 3 4 
assignment operator 3 4 
a 3 
a 3 
a 3 
b 4 
b 4 
b 4 

Xem Olis câu trả lời cho lý do tại sao.

+0

@SteveChỉ bạn đã đúng, tôi đã sửa nó. – RedX

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