将值从本地堆栈移动到堆? (C++)
如何从方法调用中获取对象即值结果并将其放置在堆上?
例如:
Qt QImage::scaledToWidth
方法 返回 QImage
对象的副本。
我现在在想:
QImage *new_img_on_heap = new QImage(old_imgage_on_heap->scaledToWidth(2000));
这是唯一的方法吗?当我已经在堆栈上有了一个完美的好对象时,似乎它正在经历制作第三个全新对象的麻烦。
我想把它放在堆上的原因是因为真正的 QImage 很大,并且我希望它比当前方法的生命周期更长。我打算在我的班级的一个字段中填充一个指向它的指针。
我知道 QImage 具有某种隐式数据共享,但我不太清楚它在幕后是如何工作的。另外,如果我需要使用设计不如 Qt 的对象,我想知道一个通用的解决方案。
How can I take an object-as-value result from a method call and place it on the heap?
For instance:
The Qt QImage::scaledToWidth
method returns a copy of the QImage
object.
Right now I'm doing:
QImage *new_img_on_heap = new QImage(old_imgage_on_heap->scaledToWidth(2000));
Is this the only way? Seems like it's going through the trouble of making a 3rd whole new object when I already have a perfect good one on the stack.
The reason I want to put it on the heap is because the real QImage
is large, and I want it to outlive the lifetime of the current method. I was intending to stuff a pointer to it in a field of my class.
I know that QImage
has some sort of implicit data sharing, but I'm not exactly clear on how it works under the hood. Plus, I wanted to know a general solution should I ever need to use objects not as well designed as Qt's.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对象由其地址来标识。如果你想在另一个地方
地址,你必须建造一个新的;你不能移动物体。 (甚至
对于 C++11,新的“移动”语义实际上并不移动
目的;如果您知道的话,它们提供了一种转移其价值的优化方式
您不需要将其移动到的位置的值。)
An object is identified by its address. If you want it at another
address, you have to construct a new one; you can't move objects. (Even
with C++11, the new “move” semantics don't actually move an
object; they provide an optimized way of moving its value, if you know
that you won't need the value from where you're moving it.)
首先,在大多数情况下,您应该更喜欢堆栈而不是堆。
其次,当您在堆上分配对象时,您应该将原始指针包装在堆栈上的某个托管对象中。如果不为别的,那就为了异常安全而这样做。
第三,Qt对象通常正是这样做的,即编写没有任何优势
new QImage
或new QMap
等。不过,将非堆对象移动到堆上的正确方法是
如果您使用临时对象执行此操作,这样的那么
它可能会删除额外的副本 (链接对我而言已损坏 - 缓存)
Firstly, you should prefer the stack to the heap in most cases.
Secondly, when you allocate objects on the heap you should wrap the raw pointer in some managed object which is on the stack. If for nothing else, do it for exception safety.
Thirdly, Qt objects usually do exactly that i.e. there's no advantage in writing
new QImage
ornew QMap<int>
etc.Nevertheless the right way to move a non-heap object onto the heap is to say
If you do this with a temporary object, such as
then it will probably elide the extra copy (link broken for me -- cached)
由于方法
QImage QImage::scaledToWidth ( int width, Qt::TransformationMode mode = Qt::FastTransformation ) const
不会返回 QImage 地址(即 QImage& ....),所以我认为你不走运。你被副本困住了。除非您想重新编译 QT 库来更改该函数签名,以便它不返回副本。
无论如何,将该对象放在堆栈上有什么不好?
Since the method
QImage QImage::scaledToWidth ( int width, Qt::TransformationMode mode = Qt::FastTransformation ) const
does not return a QImage address (i.e. QImage& ....) than I think you are out of luck. You are stuck with a copy. Unless you want to recompile the QT libraries to change that function signature so that it does not return a copy.
What is so bad about having that object on the stack anyways?
你可以尝试下面的技巧。想法是将您的值放入某些结构并在堆中构造结构。在这种情况下,复制省略有效。不执行任何复制或移动。不幸的是它在 VS2017 上不起作用。但它可以在 G++ 8+ 中运行,也可能在 VS2019 中运行。
You can try following trick. Idea is to put your value to some structure and construct structure in heap. In this case copy elision works. No copies or moves are performed. Unfortunately it does not work on VS2017. But it works in G++ 8+ and probably in VS2019.
这个问题的前提是不正确的,因为它假设 QImage 的图像数据与 QImage 对象本身具有相同的生命周期。
这个说法不正确,因为对于像 QImage 这样的东西来说,这将是一件非常糟糕的事情,并且很快就会因弹出“堆栈”限制而失败。这也会使作业变得非常慢!
相反,QImage 与许多处理大型和/或外部数据的 C++ 对象一样,实际上是不同生命周期的内部管理内存的包装器。这可以在QImage源代码中看到< /a>; QImage 包含 QImageData,并且 QImageData malloc 的内部缓冲区与原始 QImage 的生命周期无关。
由于大部分数据位于 QImage“外部”,因此没有理由更喜欢 new QImage 而不是使用 QImage 和自动生命周期(错误地理解)图像数据的存储期限; QImage 实现了理智的复制和移动*,以便共享所有底层图像数据(及其底层分配)。
*在QImage的复制构造器中QImageData 的“引用计数”会短暂延长,直到前一个对象被销毁为止,而在移动过程中,QImageData 的生命周期可以直接转移(在注释中,缺少该对象) 来源?)。无论如何,这两种情况实际上都会复制底层图像数据,这将是昂贵的。
因此,要回答这个问题:
new X(non_ptr_X)
,并让正确编写的构造函数/设计完成它们的工作,这是一个实现细节;希望是令人满意的性能特征之一。 YMMV。The premise of this question/ask is incorrect in that it assumes that the image data for QImage has the same lifetime of the QImage object itself.
This statement is not correct as it would be a VERY BAD thing for something like QImage, and very quickly fail by popping "stack" limits. It would also make assignments very slow!
Rather, QImage, like many C++ objects that deal with large and/or external data, is effectively a wrapper around internally managed memory of a different lifetime. This can be seen in the QImage source code; QImage contains QImageData, and QImageData malloc's the internal buffer independently of the original QImage's lifetime.
As the bulk of the data is "outside" of QImage, there is little reason to prefer
new QImage
instead of usingQImage
and auto lifetimes for sake of the (incorrectly perceived) storage duration of the image data; QImage implements copy and move sanely*, so that all underlying image data (and underlying allocation of such) is shared.*In QImage's copy ctor the 'ref count' of the QImageData is briefly extended until the destruction of the previous object, while in the move the QImageData's lifetime could be directly transferred (in comment, missing from that source?). Regardless, neither case actually makes a copy of the underlying image data which would be expensive.
So, to answer the question:
new X(non_ptr_X)
, and let the properly written constructors/design do their thing, which is an implementation detail; and hopefully one of agreeable performance characteristics. YMMV.