C ++ std :: unique_ptr但不可移动?

时间:2014-03-04 19:10:41

标签: c++ c++11 unique-ptr

我正在使用std :: unique_ptr在类上创建一些公共成员,这些成员必须是不可复制的或可移动的。但是std :: unique_ptr是可移动的,我想知道如果有人移动std :: unique_ptr包含的指针然后我尝试访问被移动的那个类的std :: unique_ptr成员会发生什么。

示例代码:

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

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

    }

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

    std::string id;
};

struct objs
{
    // They must stay here no mater what.
    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") ))
    {

    }

    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;
}

应用程序崩溃,因为当然导致我的问题。我怎样才能防范这种情况?

对象必须是公共的,不是常量,不能移动或复制。有问题的实际对象使用可变参数模板,我宁愿不使用旧方法在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;
       ^

2 个答案:

答案 0 :(得分: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")
            {}

};

答案 1 :(得分:0)

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

此代码预计会使obx处于未指定状态,因此您不应尝试再次访问它,而应尝试访问newb。如果您不希望移动包含的unique_ptr,则不要移动其容器obx。或者,如果要定义(或禁用)移动struct objs的语义,则提供自己的移动构造函数(赋值等)或删除默认值(取决于您要执行的操作)