无法移动而无法从函数返回std :: unique_ptr

har*_*mic 3 c++ unique-ptr

我正在更新一些auto_ptr用来unique_ptr代替的旧代码。它主要是一个搜索和替换工作,但是我发现我在代码返回a的一个地方遇到了编译错误unique_ptr

这是说明问题的示例:

#include <string>
#include <iostream>
#include <memory>
#include <utility>

using namespace std;

struct Foo {
    unique_ptr<string> us;

    Foo() {
        this->us = unique_ptr<string>(new string("hello"));
    }

    unique_ptr<string> bar() {
        return this->us;
    }

};


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

    Foo foo;
    unique_ptr<string> s = foo.bar();
    cout << *s << endl;

}
Run Code Online (Sandbox Code Playgroud)

当我编译它时,我得到了:

t1.cpp: In member function ‘std::unique_ptr<std::basic_string<char> > Foo::bar()’:
t1.cpp:17:16: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = std::basic_string<char>; _Dp = std::default_delete<std::basic_string<char> >]’
   return this->us;
                ^~
In file included from /opt/rh/devtoolset-7/root/usr/include/c++/7/memory:80:0,
                 from t1.cpp:4:
/opt/rh/devtoolset-7/root/usr/include/c++/7/bits/unique_ptr.h:388:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

如果我更改错误行以指定这样的移动:

        return move(this->us);
Run Code Online (Sandbox Code Playgroud)

然后就可以了。

我发现有许多参考资料表明不需要采取任何举动-例如,这个SO问题,以及来自铬项目的这些准则

我的问题是:在这种情况下,为什么需要明确指定举动?我以某种方式返回实例变量的值是否与事实有关?

如果这是骗人的话,请提前道歉-我敢肯定会问过这个问题,但是我很难找到能找到它的搜索词。

Chr*_*phe 6

这都是关于语义的。A unique_ptr唯一的所有权,因此将返回或在中us,但不能同时返回。该标准的规则幸运地保护您免受这种误解。

您可以做的是返回一个临时文件unique_ptr(将被移动):

unique_ptr<string> bar() {
    return make_unique<string>("hello, world");
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您需要unique_ptr在多个地方复制一份,根据您的情况似乎如此main(),那么您并不是在寻找唯一的而是共享的所有权。因此,您应该转到shared_ptr

struct Foo {
    shared_ptr<string> us;

    Foo() {
        us = make_shared<string>("hello, world");
    }
    shared_ptr<string> bar() {
        return us;
    }
};

int main(int argc, const char **argv) {
    Foo foo;
    auto s = foo.bar();
    cout << *s << endl;
}
Run Code Online (Sandbox Code Playgroud)


Sto*_*ica 5

您找到的所有引用都提到返回的对象必须是函数局部变量。您返回一个成员。返回时,成员变量不会被隐式视为右值。

这不是没有道理的。除非明确声明,一个类通常不想失去其资源的所有权。

当函数返回时,无论如何局部函数都会死掉,因此让编译器隐式地蚕食它是一个值得优化的优化。