如何正确地将所有权从原始指针移动到 std::unique_ptr?
How to correctly move ownership from raw pointer to std::unique_ptr?
我的做法是:
class SomeClass
{
std::vector<std::unique_ptr<MyObject>> myObjects;
public:
void takeOwnership(MyObject *nowItsReallyMyObject)
{
myObjects.emplace_back(std::move(nowItsReallyMyObject));
}
};
我做的是否正确,或者有更好的解决方案吗?
您应该从一开始就接受unique_ptr
:
class SomeClass
{
std::vector<std::unique_ptr<MyObject>> myObjects;
public:
// tells the world you 0wNz this object
void takeOwnership(std::unique_ptr<MyObject> myObject)
{
myObjects.push_back(std::move(myObject));
}
};
通过这种方式,您可以清楚地表明您拥有所有权,还可以帮助其他程序员避免使用原始指针。
进一步阅读:CppCoreGuidelines R.32
move
是多余的。
我自己,我会这样做:
void takeOwnership(std::unique_ptr<MyObject> nowItsReallyMyObject)
{
myObjects.emplace_back(std::move(nowItsReallyMyObject));
}
因为我想尽可能 "out" 移动 unique_ptr
所有权语义。
我可能会写这个效用函数:
template<class T>
std::unique_ptr<T> wrap_in_unique( T* t ) {
return std::unique_ptr<T>(t);
}
所以呼叫者可以:
foo.takeOwnership(wrap_in_unique(some_ptr));
但更好的是,可以将 unique_ptr
语义的边界尽可能地推开。
我什至可以:
template<class T>
std::unique_ptr<T> wrap_in_unique( T*&& t ) {
auto* tmp = t;
t = 0;
return std::unique_ptr<T>(tmp);
}
template<class T>
std::unique_ptr<T> wrap_in_unique( std::unique_ptr<T> t ) {
return std::move(t);
}
这让呼叫者可以更轻松地将他们的 T*
转换为 unique_ptr
。他们所有的 T*
->unique_ptr<T>
现在都包裹在 std::move
中,并将源指针归零。
所以如果他们有
struct I_am_legacy {
T* I_own_this = 0;
void GiveMyStuffTo( SomeClass& sc ) {
sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
}
};
代码可以转化为:
struct I_am_legacy {
std::unique_ptr<T> I_own_this;
void GiveMyStuffTo( SomeClass& sc ) {
sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
}
};
它仍然可以编译并且工作相同。 (与 I_own_this
的其他交互可能需要更改,但其中一部分已经 unique_ptr 兼容)。
我的做法是:
class SomeClass
{
std::vector<std::unique_ptr<MyObject>> myObjects;
public:
void takeOwnership(MyObject *nowItsReallyMyObject)
{
myObjects.emplace_back(std::move(nowItsReallyMyObject));
}
};
我做的是否正确,或者有更好的解决方案吗?
您应该从一开始就接受unique_ptr
:
class SomeClass
{
std::vector<std::unique_ptr<MyObject>> myObjects;
public:
// tells the world you 0wNz this object
void takeOwnership(std::unique_ptr<MyObject> myObject)
{
myObjects.push_back(std::move(myObject));
}
};
通过这种方式,您可以清楚地表明您拥有所有权,还可以帮助其他程序员避免使用原始指针。
进一步阅读:CppCoreGuidelines R.32
move
是多余的。
我自己,我会这样做:
void takeOwnership(std::unique_ptr<MyObject> nowItsReallyMyObject)
{
myObjects.emplace_back(std::move(nowItsReallyMyObject));
}
因为我想尽可能 "out" 移动 unique_ptr
所有权语义。
我可能会写这个效用函数:
template<class T>
std::unique_ptr<T> wrap_in_unique( T* t ) {
return std::unique_ptr<T>(t);
}
所以呼叫者可以:
foo.takeOwnership(wrap_in_unique(some_ptr));
但更好的是,可以将 unique_ptr
语义的边界尽可能地推开。
我什至可以:
template<class T>
std::unique_ptr<T> wrap_in_unique( T*&& t ) {
auto* tmp = t;
t = 0;
return std::unique_ptr<T>(tmp);
}
template<class T>
std::unique_ptr<T> wrap_in_unique( std::unique_ptr<T> t ) {
return std::move(t);
}
这让呼叫者可以更轻松地将他们的 T*
转换为 unique_ptr
。他们所有的 T*
->unique_ptr<T>
现在都包裹在 std::move
中,并将源指针归零。
所以如果他们有
struct I_am_legacy {
T* I_own_this = 0;
void GiveMyStuffTo( SomeClass& sc ) {
sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
}
};
代码可以转化为:
struct I_am_legacy {
std::unique_ptr<T> I_own_this;
void GiveMyStuffTo( SomeClass& sc ) {
sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
}
};
它仍然可以编译并且工作相同。 (与 I_own_this
的其他交互可能需要更改,但其中一部分已经 unique_ptr 兼容)。