2013-07-05 33 views
9

Tôi có một lớp có điểm tới mảng được phân bổ động, vì vậy tôi đã tạo hàm tạo bản sao và hàm toán tử gán. Vì hàm tạo bản sao và hàm toán tử gán làm cùng một công việc, tôi gọi hàm tạo bản sao từ hàm toán tử gán nhưng nhận được "error C2082: redefinition of formal parameter". Tôi đang sử dụng Visual Studio 2012.hàm tạo bản sao cuộc gọi từ hàm điều hành gán

// default constructor 
FeatureValue::FeatureValue() 
{ 
    m_value = NULL; 
} 

// copy constructor 
FeatureValue::FeatureValue(const FeatureValue& other) 
{ 
    m_size = other.m_size; 
    delete[] m_value; 
    m_value = new uint8_t[m_size]; 

    for (int i = 0; i < m_size; i++) 
    { 
     m_value[i] = other.m_value[i]; 
    } 
} 

// assignment operator function 
FeatureValue& FeatureValue::operator=(const FeatureValue& other) 
{ 
    FeatureValue(other); // error C2082: redefinition of formal parameter 
    return *this; 
} 

Trả lời

14

Đường vi phạm không phải là điều bạn nghĩ. Nó thực sự khai báo biến số other của loại FeatureValue. Điều này là do các nhà xây dựng không có tên và không thể được gọi trực tiếp.

Bạn có thể gọi toán tử gán bản sao một cách an toàn từ hàm tạo miễn là toán tử không được khai báo ảo.

FeatureValue::FeatureValue(const FeatureValue& other) 
    : m_value(nullptr), m_size(0) 
{ 
    *this = other; 
} 

// assignment operator function 
FeatureValue& FeatureValue::operator=(const FeatureValue& other) 
{ 
    if(this != &other) 
    { 
     // copy data first. Use std::unique_ptr if possible 
     // avoids destroying our data if an exception occurs 
     uint8_t* value = new uint8_t[other.m_size]; 
     int size = other.m_size; 

     for (int i = 0; i < other.m_size; i++) 
     { 
      value[i] = other.m_value[i]; 
     } 

     // Assign values 
     delete[] m_value; 
     m_value = value; 
     m_size = size; 
    } 
    return *this; 
} 

Điều này sẽ hoạt động giống dandy hoặc bạn có thể sử dụng các hướng dẫn điển hình cho các bản sao & hoán đổi thành ngữ đề xuất trong Vaughn Cato's answer

+0

tại sao không chỉ 'm_value [i] = other.m_value [i]' thay vì sử dụng giá trị trung gian, ví dụ: 'value [i] = other.m_value [i]'? – stackunderflow

11

Bạn không thể gọi trực tiếp cho nhà xây dựng giống như bất kỳ phương pháp nào khác. Những gì bạn đang làm thực sự tuyên bố một biến được gọi là other của loại FeatureValue.

Hãy nhìn vào các thành ngữ sao chép và trao đổi một cách tốt để tránh trùng lặp giữa các nhà điều hành phân công và các nhà xây dựng bản sao: What is the copy-and-swap idiom?

Thậm chí tốt hơn, sử dụng một std::vector thay vì newdelete. Sau đó, bạn không cần phải viết trình tạo bản sao của riêng bạn hoặc toán tử gán.

+0

Đó là liên kết lại! –

+0

Thật lạ lùng khi các bạn trả lời cùng một điều cùng một lúc. – Borgleader

+0

@Borgleader những gì bạn có thể tìm thấy thậm chí còn kỳ lạ hơn là tôi đã biết về Vaughn trong hơn 25 năm. Anh ta không biết gì về tôi;) –

3

Câu trả lời ngắn - không làm điều đó.

chi tiết:

// copy constructor 
FeatureValue::FeatureValue(const FeatureValue& other) 
{ 
    m_size = other.m_size; 
    delete[] m_value;  // m_value NOT INITIALISED - DON'T DELETE HERE! 
    m_value = new uint8_t[m_size]; 

    for (int i = 0; i < m_size; i++) 
    { 
     m_value[i] = other.m_value[i]; 
    } 
} 

// assignment operator function 
FeatureValue& FeatureValue::operator=(const FeatureValue& other) 
{ 
    FeatureValue(other); // error C2082: redefinition of formal parameter 
    return *this; 
} 

Ghi chú:

  • Khi copy constructor được gọi, nó xây dựng các đối tượng mới với tham chiếu đến các đối tượng được sao chép, nhưng các nhà xây dựng mặc định không chạy trước copy constructor. Điều này có nghĩa là m_value có giá trị không xác định khi hàm khởi tạo sao chép bắt đầu chạy - bạn có thể gán cho nó, nhưng để đọc từ đó là hành vi không xác định, và đến delete[] nó tệ hơn nhiều (nếu có điều gì tệ hơn UD! ;-)). Vì vậy, chỉ cần bỏ ra rằng delete[] dòng.

Tiếp theo, nếu operator= cố gắng tận dụng chức năng từ trình tạo bản sao, trước tiên phải phát hành mọi dữ liệu hiện có m_value đang trỏ hoặc sẽ bị rò rỉ. Hầu hết mọi người cố gắng làm điều đó như sau (mà được chia) - Tôi nghĩ rằng đây là những gì bạn đang cố gắng cho:

FeatureValue& FeatureValue::operator=(const FeatureValue& other) 
{ 
    // WARNING - this code's not exception safe...! 
    ~FeatureValue(); // call own destructor 
    new (this) FeatureValue(other); // reconstruct object 
    return *this; 
} 

Vấn đề ở đây là nếu việc tạo ra các FeatureValue không (ví dụ vì new thể không nhận được bộ nhớ nó muốn), sau đó các đối tượng FeatureValue là trái với một nhà nước không hợp lệ (ví dụ: m_value có thể được chỉ ra vào không gian). Sau đó khi destructor chạy và thực hiện delete[] m_value, bạn có hành vi không xác định (chương trình của bạn có thể sẽ bị lỗi).

Bạn thực sự nên tiếp cận điều này một cách có hệ thống hơn ...hoặc viết nó ra từng bước, hoặc có lẽ thực hiện một đảm bảo không ném phương pháp swap() (dễ dàng để làm ... chỉ std::swap()m_sizem_value, và sử dụng nó ala:

FeatureValue& FeatureValue::operator=(FeatureValue other) 
{ 
    swap(other); 
    return *this; 
} 

Đó là dễ dàng và sạch sẽ, nhưng nó có một cặp vợ chồng nhỏ vấn đề hiệu suất/hiệu quả:

  • giữ bất kỳ m_value mảng hiện xung quanh lâu hơn cần thiết, tăng sử dụng bộ nhớ cao điểm ... bạn có thể gọi clear() Trong thực tế, hầu hết các chương trình không tầm thường sẽ không quan tâm. về điều này trừ khi dat một cấu trúc được đề cập đang chứa lượng dữ liệu khổng lồ (ví dụ: hàng trăm megabyte hoặc gigabyte cho một ứng dụng PC).

  • thậm chí không cố gắng sử dụng lại bộ nhớ hiện tại m_value - thay vào đó luôn thực hiện new khác cho other (có thể dẫn đến giảm mức sử dụng bộ nhớ nhưng không phải lúc nào cũng đáng giá).

Cuối cùng, lý do có thể có khác biệt constructor sao chép và operator= - thay vì phải trình biên dịch tự động tạo ra một từ khác - đó là triển khai một cách tối ưu hiệu quả có thể không - nói chung - đòn bẩy nhau trong cách bạn đã hy vọng.

0

Tuyên bố FeatureValue(other); thực sự gọi hàm tạo bản sao để tạo đối tượng Featurevalue mới, không liên quan gì với *this.

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