gpt4 book ai didi

c++ - 我应该使用指针还是 move 语义来传递大块数据?

转载 作者:可可西里 更新时间:2023-11-01 15:57:14 25 4
gpt4 key购买 nike

我对推荐的编码技术有疑问。我有一个模型分析工具,有时需要传递大量数据(从工厂类到包含多个异构块的类)。

我的问题是是否就我应该使用指针还是 move 所有权达成共识(我需要尽可能避免复制,因为数据块的大小可能高达 1 GB)。

指针版本如下所示:

class FactoryClass {
...
public:
static Data * createData() {
Data * data = new Data;
...
return data;
}
};

class StorageClass {
unique_ptr<Data> data_ptr;
...
public:
void setData(Data * _data_ptr) {
data_ptr.reset(_data_ptr);
}
};

void pass() {
Data * data = FactoryClass::createData();
...
StorageClass storage;
storage.setData(data);
}

而 move 版本是这样的:
class FactoryClass {
...
public:
static Data createData() {
Data data;
...
return data;
}
};

class StorageClass {
Data data;
...
public:
void setData(Data _data) {
data = move(_data);
}
};

void pass() {
Data data = FactoryClass::createData();
...
StorageClass storage;
storage.setData(move(data));
}

我更喜欢 move 版本 - 是的,我需要向主代码添加 move 命令,但最终我只有存储中的对象,我不再需要关心指针语义。

但是,在使用我不详细了解的 move 语义时,我并不太放松。 (不过我不关心 C++11 的要求,因为代码已经只能编译 Gcc4.7+)。

有人会有支持任一版本的引用吗?或者还有其他一些关于如何传递数据的首选版本?

我无法搜索任何内容,因为关键字通常会指向其他主题。

谢谢。

编辑注意:
第二个示例被重构以包含来自评论的建议,语义保持不变。

最佳答案

当您将对象传递给函数时,传递的内容部分取决于该函数将如何使用它。函数可以通过以下三种一般方式之一使用对象:

  • 它可以在函数调用期间简单地引用对象,调用函数(或者它是调用堆栈上的最终父级)维护对象的所有权。这种情况下的引用可以是常量引用或可修改引用。该函数不会长期存储此对象。
  • 它可以直接复制对象。它不会获得原件的所有权,但会获得原件的拷贝,以便存储、修改或处理拷贝。请注意,#1 和 this 之间的区别在于参数列表中的拷贝是显式的。例如,取一个 std::string按值(value)。但这也可以像获取 int 一样简单。按值(value)。
  • 它可以获得对象的某种形式的所有权。然后,该函数对对象的销毁负有一定的责任。这也允许函数长期存储对象。

  • 我对这些范例的参数类型的一般建议如下:
  • 在可能的情况下通过显式语言引用获取对象。如果这不可能,请尝试 std::reference_wrapper .如果这行不通,并且没有其他解决方案似乎合理,则使用指针。指针将用于诸如可选参数之类的东西(尽管 C++14 的 std::optional 会使它变得不那么有用。虽然指针仍然有用)、语言数组(尽管同样,我们有对象涵盖了这些的大部分用途),等等。
  • 按值获取对象。那是相当不可商量的。
  • 通过值 move (即:将其 move 到按值参数中)或通过指向对象的智能指针(也将按值获取,因为无论如何您都将复制/move 它)获取对象.您的代码的问题在于您通过指针转移所有权,但使用原始指针。原始指针没有所有权语义。分配任何指针的那一刻,您应该立即将其包装在某种智能指针中。所以你的工厂函数应该返回一个 unique_ptr .

  • 你的情况似乎是#3。您在值 move 和智能指针之间使用哪个完全取决于您。如果必须堆分配 Data出于某种原因,那么选择几乎是为您做出的。如 Data可以堆栈分配,然后你有一些选择。

    我通常会根据 Data 的估计来执行此操作。的内部尺寸。如果在内部,它只是几个指针/整数(“很少”,我的意思是 3-4),那么将它放在堆栈中就可以了。

    确实,它可以更好,因为双缓存未命中的机会更少。如果您的 Data如果您存储 Data,函数通常只是从另一个指针访问数据。通过指针,那么对它的每个函数调用都必须取消引用您存储的指针以获取内部指针,然后取消引用内部指针。这是两个潜在的缓存未命中,因为两个指针都没有与 StorageClass 的任何位置。 .

    如果您存储 Data按值(value)计算, Data 的可能性更大的内部指针将已经在缓存中。与 StorageClass 有更好的局部性的其他成员;如果您访问了 StorageClass 的某些内容在此之前,您已经为缓存未命中付出了代价,因此您很可能已经拥有 Data在缓存中。

    但运动不是自由的。它比完整版便宜,但不是免费的。您仍在复制内部数据(并且可能会清除原始数据上的任何指针)。但话又说回来,在堆上分配内存也不是免费的。也不是解除分配。

    但话又说回来,如果您不经常 move 它(您 move 它以使其到达最终位置,但之后再 move 一点),即使 move 更大的物体也没有问题。如果您使用它的次数超过 move 它的次数,那么对象存储的缓存位置可能会胜过 move 的成本。

    最终没有太多技术原因可以选择其中之一。我会说在合理的情况下默认 move 。

    关于c++ - 我应该使用指针还是 move 语义来传递大块数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17928687/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com