2014-03-04 196 views
2

我正在使用std :: unique_ptr在類上創建一些公共成員,並且這些成員必須是不可複製或可移動的。但std :: unique_ptr是可移動的,我想知道如果有人會移動std :: unique_ptr包含的指針會發生什麼,然後嘗試訪問被移動的那個類的std :: unique_ptr成員。C++ std :: unique_ptr但不可移動?

示例代碼:

​​

自然是因爲這使我對我的問題的應用程序崩潰。我該如何防範呢?

對象必須是公共的,而不是常量,無法移動或複製。有問題的實際對象使用可變參數模板,我寧願不要在obj中使用靜態成員函數create()的舊方法,然後保護構造函數。 此外,我需要避免geters和setter,因爲類使用可變參數模板,並使代碼醜陋地獄。

我需要的是讓std :: unique_ptr不可移動,並且只保存一個唯一的指針,該指針永遠不能從擁有它的類中移動或複製。

有問題的實際代碼是來自Nano-signal-slot庫的Nano :: signal類。 (萬一有人需要實際的代碼

編輯: 改編使用Nevin的方法,並使其工作。我已經發布了代碼,因爲Nevin在容器上實現它而不是對象。

#include <cstdlib> 
#include <memory> 
#include <string> 
#include <iostream> 

struct obj 
{ 
    obj(std::string id) 
     : id(id) 
    { 

    } 

    obj(obj const&) = delete; 
    obj& operator=(obj const&) = delete; 
    obj& operator=(obj&&) = delete; 
    obj(obj&&) = delete; 


    void identif() 
    { 
     std::cout << "i am " << id << std::endl; 
    } 

    std::string id; 
}; 

struct objs 
{ 
    const std::unique_ptr<obj> obj_a; 
    const std::unique_ptr<obj> obj_b; 
    const std::unique_ptr<obj> obj_c; 

    objs() 
     : obj_a(std::unique_ptr<obj>(new obj("object a"))) 
      ,obj_b(std::unique_ptr<obj>(new obj("object b"))) 
      ,obj_c(std::unique_ptr<obj>(new obj("object c"))) 
    { 

    } 

    void do_a() 
    { 
     std::cout << " member: " << obj_a->id << std::endl; 
     std::cout << " method: "; 
     obj_a->identif(); 
    } 

    void do_b() 
    { 
     std::cout << " member: " << obj_b->id << std::endl; 
     std::cout << " method: "; 
     obj_b->identif(); 
    } 

    void do_c() 
    { 
     std::cout << " member: " << obj_c->id << std::endl; 
     std::cout << " method: "; 
     obj_c->identif(); 
    } 
}; 

int main(int argc, char** argv) 
{ 

    objs obx; 

    std::cout << " before move: " << std::endl; 

    obx.do_a(); 
    obx.do_b(); 
    obx.do_c(); 

    std::cout << " after move: " << std::endl; 

    std::unique_ptr<obj> newb(std::move(obx.obj_b)); 

    obx.do_a(); 
    obx.do_b(); 
    obx.do_c(); 

    return EXIT_SUCCESS; 
} 

這個現在應該產生:

main.cpp: In function 'int main(int, char**)': 
main.cpp:77:53: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = obj; _Dp = std::default_delete<obj>]' 
    std::unique_ptr<obj> newb(std::move(obx.obj_b)); 
                ^
In file included from /usr/include/c++/4.8/memory:81:0, 
       from main.cpp:2: 
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here 
     unique_ptr(const unique_ptr&) = delete; 
    ^
+4

爲什麼你不能讓它們成爲'const'? – Praetorian

+0

嗯,這實際上工作。我認爲,使std :: unique_ptr常量也會使obj常量和obj將無法通過方法修改它的成員。吮吸像我這樣的小菜:)謝謝。 –

+2

如果你不想讓人們與你的數據成員混在一起,你爲什麼要把它們放在「公共」的位置?封裝的全部目的是防止這種事情發生。 –

回答

5

只是要objs不可複製和不可移動的,如:

struct objs 
{ 
    objs(objs const&) = delete; 
    objs& operator=(objs const&) = delete; 
    objs& operator=(objs&&) = delete; 
    objs(objs&&) = delete; 

    std::unique_ptr<obj> obj_a; 
    std::unique_ptr<obj> obj_b; 
    std::unique_ptr<obj> obj_c; 

    objs() 
     : obj_a(std::unique_ptr<obj>(new obj("object a"))) 
      ,obj_b(std::unique_ptr<obj>(new obj("object b"))) 
      ,obj_c(std::unique_ptr<obj>(new obj("object c"))) 
     {} 

}; 

而且,一旦你做到了這一點,有內部也不需要指針。您可以簡化代碼:

struct objs 
{ 
    objs(objs const&) = delete; 
    objs& operator=(objs const&) = delete; 
    objs& operator=(objs&&) = delete; 
    objs(objs&&) = delete; 

    obj obj_a; 
    obj obj_b; 
    obj obj_c; 

    objs() 
     : obj_a("object a") 
      ,obj_b("object b") 
      ,obj_c("object c") 
      {} 

}; 
+0

它實際上是不能移動的obj(對象),而不是objs(容器)。但我現在正在測試這個。謝謝:) –

+1

[This does not work。](http://coliru.stacked-crooked.com/a/003e7a49a4598802)使課程不可複製/不可移動並不意味着其成員不能移動。 – Praetorian

+0

我已經將它翻譯成對象並且它可以工作。std :: unique_ptr < obj > newb(std :: move(obx.obj_b));不起作用。 http://coliru.stacked-crooked.com/a/a470a7230b37c9db –

0
newb(std::move(obx.obj_b)) 

此代碼預計離開obx在未指定狀態,所以你不應該再次嘗試訪問它,而嘗試訪問newb。如果您不希望移動包含的unique_ptr,請勿移動其容器obx。或者,如果您想要定義移動結構的語義(或禁用),請根據您要執行的操作提供您自己的移動構造函數(賦值等)或刪除默認的移動構造函數。