2015-11-28 17 views
13

Hãy nói rằng tôi có hệ thống phân cấp sau các lớp:Cách đúng trở về std :: unique_ptr đến một đối tượng của lớp đa hình

struct Base 
{ 
}; 

struct Derived : public Base 
{ 
    void DoStuffSpecificToDerivedClass() 
    { 
    } 
}; 

Và phương pháp nhà máy sau:

std::unique_ptr<Base> factoryMethod() 
{ 
    auto derived = std::make_unique<Derived>(); 
    derived->DoStuffSpecificToDerivedClass(); 
    return derived; // does not compile 
} 

Vấn đề là, câu lệnh return không biên dịch, bởi vì std::unique_ptr không có một hàm tạo bản sao với sự hỗ trợ hiệp phương sai (có ý nghĩa vì nó không có bất kỳ trình tạo bản sao nào), nó chỉ có một hàm tạo di chuyển với sự hỗ trợ hiệp phương sai.

Cách tốt nhất để giải quyết vấn đề này là gì? Tôi có thể nghĩ đến hai cách:

return std::move(derived); // this compiles 
return std::unique_ptr<Base>(derived.release()); // and this compiles too 

EDIT 1: Tôi đang sử dụng Visual C++ 2013 như trình biên dịch của tôi. Thông báo lỗi ban đầu cho return derived trông như thế này:

Error 1 error C2664: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'std::unique_ptr<Derived,std::default_delete<Derived>>' to 'std::unique_ptr<Derived,std::default_delete<Derived>> &&' 

EDIT 2: Nó là một giao diện điều khiển ứng dụng mới được tạo ra từ một tiêu chuẩn VS 2013 mẫu. Tôi chưa tinh chỉnh bất kỳ cài đặt trình biên dịch nào. dòng lệnh biên dịch trông như thế này:

gỡ lỗi:

/Yu"stdafx.h" /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd"Debug\vc120.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\CppApplication1.pch" 

phát hành:

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\CppApplication1.pch" 
+0

Biên dịch tốt với VC++ 2013. Đăng một MCVE và cho chúng tôi biết cách bạn gọi trình biên dịch. –

+0

@ChristianHackl Tôi đã thêm thông tin dòng lệnh trình biên dịch vào câu hỏi của mình. Nhân tiện, C++ Shell không biên dịch: http://cpp.sh/8lxwn –

+0

Vẫn không có MCVE. http://stackoverflow.com/help/mcve –

Trả lời

8

Bạn có thể làm điều này:

return std::move(derived); 

Bằng cách đó bạn nói với trình biên dịch không có bản sao là cần thiết, đáp ứng các yêu cầu của unique_ptr. Nếu các loại phù hợp hoàn hảo, bạn không cần phải chỉ định rõ ràng move, nhưng trong trường hợp này bạn làm.

+0

OP đã biết về giải pháp này. Và nó dường như không hiệu quả với anh ta. Đó là tất cả trong câu hỏi. –

+0

"Nếu các loại phù hợp hoàn hảo, bạn không cần phải chỉ định rõ ràng di chuyển, nhưng trong trường hợp này bạn làm" - câu trả lời cho câu hỏi của tôi. Tôi không biết rằng di chuyển tiềm ẩn chỉ xảy ra khi các loại khớp hoàn hảo. Cảm ơn. –

5

Như đã nêu trong câu hỏi, vấn đề là, câu lệnh trả về không biên dịch, std::unique_ptr không có một hàm tạo bản sao với hỗ trợ hiệp phương sai, nó chỉ có một hàm tạo di chuyển với hỗ trợ hiệp phương sai, tuy nhiên, trình biên dịch vẫn không di chuyển từ std::unique_ptr<Derived>. Đó là vì các điều kiện để di chuyển từ một đối tượng được trả về từ một hàm được gắn chặt với các tiêu chí cho phép sao chép bản sao, đòi hỏi nghiêm ngặt loại đối tượng được trả về cần phải giống như kiểu trả về của hàm.

[class.copy]/32:

Khi các tiêu chuẩn cho sự bỏ bớt một hoạt động sao chép được đáp ứng hoặc sẽ gặp tiết kiệm cho một thực tế rằng các đối tượng nguồn là một tham số chức năng, và đối tượng được sao chép được chỉ định bởi một giá trị, quá tải độ phân giải để chọn hàm tạo cho bản sao được thực hiện lần đầu tiên như thể đối tượng được chỉ định bởi một giá trị.

Vì vậy, tôi thích,

return std::move(derived); 

Tuy nhiên, có sự thay đổi quy tắc trong DR-9R5 để các giá trị trả về sẽ được coi như một rvalue ngay cả khi các loại không giống nhau, gcc-5 thực hiện quy tắc và bạn không cần phải thay đổi mã của mình cho gcc-5 như được hiển thị here.

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