简体   繁体   English

移动 unique_ptr 的内容

[英]moving the content of a unique_ptr

So if I have a moveable (rval) std::unique_ptr, can I use simple assign to move the contents rather than copy?所以如果我有一个可移动的 (rval) std::unique_ptr,我可以使用简单的赋值来移动内容而不是复制吗? (The contents of the pointed to object, rather than the pointer to it) (指向object的内容,而不是指向它的指针)

It doesn't look like I can, but "maybe I'm doing it wrong"?看起来我做不到,但是“也许我做错了”?

If not, what was the rationale for not allowing this?如果不是,不允许这样做的理由是什么?

Detail:细节:

So I have become the owner of a class with a method that is returning the std::map from Hell, and I really don't want to include hell.h everywhere /my/ class is used, just in the few places that really want to go there.所以我已经成为 class 的所有者,其方法是从 Hell 返回 std::map,我真的不想在所有使用 /my/ class 的地方包含 hell.h,只是在少数几个真正使用的地方想go那里。

So my thought was to change the return signature of the method from所以我的想法是改变方法的返回签名

#include "hell.h"
std::map<std::string, Hell> CopyTheObjectSpecified(...);

To

class Hell;
std::unique_ptr<std::map<std::string, Hell>> CopyTheObjectSpecified(...);

And, for the cost of a new and delete, I now don't need to detail Hell, except when the method is called, and that code will be safely scoped by unique_ptr.而且,对于 new 和 delete 的成本,我现在不需要详细说明 Hell,除非调用该方法,并且该代码将安全地由 unique_ptr 限定范围。 Given the map copy has lots of allocations, I'm not concerned about one more.鉴于 map 副本有很多分配,我不关心多一个。

(ben-v suggests I'm erecting a compile firewall around Hell - good way to look at it) (ben-v 建议我在 Hell 周围建立一个编译防火墙 - 看它的好方法)

However, one of the callers is doing:但是,其中一位来电者正在做:

void Angel(std::map<std::string, Hell>& hell)
{
  hell = CopyTheObjectSpecified(...);
}

Which used to reduce to a move assignment (or even a complete return copy elision - probably not)用于减少移动分配(甚至是完整的返回复制省略 - 可能不是)

So now I'm doing one of所以现在我正在做一个

void Angel(std::map<std::string, Hell>& hell)
{
  hell = * CopyTheObjectSpecified(...);
}

Or the more verbose, visually offensive, but trackable, and injectable almost anywhere:或者更冗长,视觉上令人反感,但几乎可以在任何地方跟踪和注射:

void Angel(std::map<std::string, Hell>& hell)
{
  hell = CopyTheObjectSpecified(...) .get()[0] ;
}

It appears to me, looking at the debugs, that the overloads of * and get() don't seem to behold that the unique_ptr is an r-val, and that the content should therefore also be returned as an r-val.在我看来,查看调试, *get()的重载似乎没有看出 unique_ptr 是一个 r-val,因此内容也应该作为 r-val 返回。

(Note that my intention here is that the rval unique_ptr instance continues to own the object it is pointing to, and will delete it when it goes out of scope as normal, but that object will stripped of its contents by the move.) (请注意,我在这里的意图是 rval unique_ptr 实例继续拥有它指向的 object,并且当它正常离开 scope 时将删除它,但是 object 将通过移动剥离其内容。)

So this is invoking copy/delete semantics instead of move semantics, which is an overhead.所以这是调用复制/删除语义而不是移动语义,这是一种开销。 I can't give the code back running slower!我不能让代码运行得更慢!

Of course I could simply add a std::move(), but that would be yet an extra smell when the original author gets it back.当然,我可以简单地添加一个 std::move(),但是当原作者取回它时,那将是一种额外的味道。 I still see "unencapsulated" std::move as smell.我仍然看到“未封装”的 std::move 作为气味。 Perhaps eventually I will get used to seeing it.也许最终我会习惯看到它。

void Angel(std::map<std::string, Hell>& hell)
{
  hell = std::move( * CopyTheObjectSpecified(...) ) ;
}

Or use the swap operation (thanks Ben Voigt)或者使用交换操作(感谢 Ben Voigt)

void Angel(std::map<std::string, Hell>& hell)
{
  hell.swap ( * CopyTheObjectSpecified(...) ) ;
}

(And yes, the best (for now) implementation for CopyTheObjectSpecified() is to actually make and return a copy, rather than return some shared_ptr const reference to the ever-changing data) (是的,CopyTheObjectSpecified() 的最佳(目前)实现是实际制作并返回一个副本,而不是返回一些对不断变化的数据的 shared_ptr const 引用)

Or I can minimally encapsulate the movability in a wrapper class for unique_ptr.或者我可以将可移动性最低限度地封装在 unique_ptr 的包装器 class 中。 Are there dangers in having a when-rval-content-movable unique_ptr?使用 when-rval-content-movable unique_ptr 有危险吗?

Currently we code to c++11. Perhaps I need the help of the later standards to do this properly?目前我们编码为 c++11。也许我需要后期标准的帮助才能正确执行此操作? But that may help me formulate a solution that is readable and transferable.但这可能会帮助我制定一个可读和可转移的解决方案。

Grr.呃。 I just want this method /out/ of /my/ class!我只想要 /my/ 类的 /out/ 这个方法! But that's not an option today.但今天这不是一个选择。

At the simplest level, it would seem there's no need for unique_ptr as std::map can be instantiated on an incomplete type just fine.在最简单的层面上,似乎不需要 unique_ptr,因为std::map可以在不完整的类型上实例化就好了。 So you can do:所以你可以这样做:

class Hell;
std::map<std::string, Hell> CopyTheObjectSpecified(...);

and you only need the #include for code that wants to put something into the map or get it out of the map (or copy/duplicate the entire map).并且您只需要 #include 代码即可将某些内容放入 map 或将其从 map 中取出(或复制/复制整个地图)。 std::map already contains a level of indirection that means it can be moved without knowing the details of the key/value types. std::map已经包含一个间接级别,这意味着它可以在不知道键/值类型的细节的情况下移动。

so所以

void Angel(std::map<std::string, Hell>& hell)
{
  hell = CopyTheObjectSpecified(...);
}

should continue to work just fine.应该继续工作就好了。

I'm not sure if my answer would help or not, but as far as I know that creating a unique_ptr means that the ownership of an object is can't be changed which means it's only valid in the scope where it has been defined/created so I think you can't move the content of it since it's going to be an ownership change.我不确定我的回答是否有帮助,但据我所知,创建unique_ptr意味着 object 的所有权无法更改,这意味着它仅在已定义的 scope 中有效/创建所以我认为你不能移动它的内容,因为它会改变所有权。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM