Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用移动语义正确管理资源? structfoo{ int*i; foo():i(新int(42)){} foo(const foo&)=删除; foo(foo&&)=默认值; ~foo(){ std::cout_C++_Move_C++14_Move Semantics - Fatal编程技术网

C++ 如何使用移动语义正确管理资源? structfoo{ int*i; foo():i(新int(42)){} foo(const foo&)=删除; foo(foo&&)=默认值; ~foo(){ std::cout

C++ 如何使用移动语义正确管理资源? structfoo{ int*i; foo():i(新int(42)){} foo(const foo&)=删除; foo(foo&&)=默认值; ~foo(){ std::cout,c++,move,c++14,move-semantics,C++,Move,C++14,Move Semantics,您需要定义move构造函数以防止从moved from对象中删除: struct foo{ int* i; foo(): i(new int(42)){} foo(const foo&) = delete; foo(foo&&) = default; ~foo(){ std::cout << "destructor: i" << std::endl; delete(i); } }; int main() {

您需要定义move构造函数以防止从moved from对象中删除:

struct foo{
  int* i;
  foo(): i(new int(42)){}
  foo(const foo&) = delete;
  foo(foo&&) = default;
  ~foo(){
    std::cout << "destructor: i" << std::endl;
    delete(i);
  }
};
int main()
{
  foo f;
  auto sp_f = std::make_shared<foo>(std::move(f));
}
现在,当运行旧对象的析构函数时,它不会删除
i
,因为删除空指针是不可操作的

您还应该定义一个移动赋值运算符,并删除复制赋值运算符。

这实际上是五条规则。如果您有一个可以从中移动的类,您应该自己定义移动语义(加上复制、析构函数等)

至于如何做到这一点,请引用“……从中移动的对象被置于有效但未指定的状态。”未指定的状态通常是对象在默认初始化时的样子,或者如果对象被调用了
swap
,会发生什么情况

正如@zenith所回答的,一种简单的方法是让移动构造函数(或赋值操作符)将原始指针设置为
nullptr
。这样,数据不会被释放,原始对象仍然处于有效状态

另一个常见的习惯用法是,如前所述,使用
swap
。如果类需要自己的复制和移动语义,那么
swap
方法也很方便。移动构造函数将初始化委托给默认构造函数,然后调用
swap
方法。在移动赋值操作符中,只需调用
swap
>。要移入的对象将获得资源,而另一个对象的析构函数将释放原始资源

通常是这样的:

foo(foo&& f): i(f.i) {
  f.i = nullptr;
}

不要默认移动构造函数?是的,实际上定义了移动cter和交换指针,例如,或者使用已经定义了移动语义的东西,比如“代码> STD::UnQuyGPPT/<代码>,而不是原始数组,只使用<代码> STD::vector < /Calp>。所有的OK。管理C++中资源的关键是使用标准RESU。rce管理器。至少要尽可能多。@chearsandhth.-Alf我在这里没有看到原始数组。在这种情况下,您可以使用
unique\u ptr I
和零规则。如果资源需要其他发布代码,您还可以使用自定义删除器使用
unique\u ptr
。避免重新发明轮子很好!如果我的用例不需要呢这么简单?如果我需要调用
delete\u某物(某个句柄)
而没有“noop”怎么办对于某些默认值并调用它两次会有问题吗?您可以始终使用布尔标志来标记是否清理资源。@MaikKlein我不太明白。您能否提供一个更详细的示例,可能在原始问题中?
class foo
可以有一个成员
bool shouldDestroy将在销毁时进行检查。如果为
true
,则销毁资源。您可以编写
std::swap(resource,rhs.resource);
struct Foo
{
    void* resource; //managed resource
    Foo() : resource(nullptr) {} //default construct with NULL resource
    Foo(Foo&& rhs) : Foo() //set to default value initially
    {
        this->swap(rhs); //now this has ownership, rhs has NULL
    }
    ~Foo()
    {
        delete resource;
    }
    Foo& operator= (Foo&& rhs)
    {
        this->swap(rhs); //this has ownership, rhs has previous resource
    }
    void swap(Foo& rhs) //basic swap operation
    {
        std::swap(resource, rhs.resource); //thanks @M.M
    }
};