将值从本地堆栈移动到堆? (C++)

发布于 2024-12-06 18:40:39 字数 561 浏览 0 评论 0原文

如何从方法调用中获取对象即值结果并将其放置在堆上?

例如:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不寐倦长更 2024-12-13 18:40:39

对象由其地址来标识。如果你想在另一个地方
地址,你必须建造一个新的;你不能移动物体。 (甚至
对于 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.)

挽清梦 2024-12-13 18:40:39

首先,在大多数情况下,您应该更喜欢堆栈而不是堆。

其次,当您在堆上分配对象时,您应该将原始指针包装在堆栈上的某个托管对象中。如果不为别的,那就为了异常安全而这样做。

第三,Qt对象通常正是这样做的,即编写没有任何优势new QImagenew QMap 等。

不过,将非堆对象移动到堆上的正确方法是

new ObjectType (old_instance)

如果您使用临时对象执行此操作,这样的那么

new ObjectType (create_object ())

它可能会删除额外的副本 (链接对我而言已损坏 - 缓存)

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 or new QMap<int> etc.

Nevertheless the right way to move a non-heap object onto the heap is to say

new ObjectType (old_instance)

If you do this with a temporary object, such as

new ObjectType (create_object ())

then it will probably elide the extra copy (link broken for me -- cached)

千柳 2024-12-13 18:40:39

由于方法

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?

彩虹直至黑白 2024-12-13 18:40:39

你可以尝试下面的技巧。想法是将您的值放入某些结构并在堆中构造结构。在这种情况下,复制省略有效。不执行任何复制或移动。不幸的是它在 VS2017 上不起作用。但它可以在 G++ 8+ 中运行,也可能在 VS2019 中运行。

#include <memory>

struct C{

    C() = default;
    C( C&& ) = delete;
    C( C const& ) = delete;

    C& operator=( C&& ) = delete;
    C& operator=( C const& ) = delete;
};

C foo() {
    return C {};
}

struct X {
    C c;

    X() 
        : c (foo()) // here is how trick works
    {
    }
};

int main() {
    auto x = std::make_unique<X>();
}

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.

#include <memory>

struct C{

    C() = default;
    C( C&& ) = delete;
    C( C const& ) = delete;

    C& operator=( C&& ) = delete;
    C& operator=( C const& ) = delete;
};

C foo() {
    return C {};
}

struct X {
    C c;

    X() 
        : c (foo()) // here is how trick works
    {
    }
};

int main() {
    auto x = std::make_unique<X>();
}
暮年 2024-12-13 18:40:39

这个问题的前提是不正确的,因为它假设 QImage 的图像数据与 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.

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.

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 using QImage 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文