【发布时间】:2019-02-05 15:49:06
【问题描述】:
我需要围绕 C++ 库编写一个 C 包装器,并且我需要在堆上分配对象。 C++ lib 的函数和方法使用并返回分配在堆栈上的对象。
我知道,我可以通过复制将一个对象从堆栈“传输”到堆,即auto heapObj = new Foo(stackObj);,但我想避免复制,如果可以的话,尝试使用move。
这似乎“有效”(令我惊讶)。幕后有副本吗?如果不是,这种模式可以安全使用吗?
main.h
class Foo {
public:
std::vector<int> big;
explicit Foo(size_t len);
Foo(Foo&& other) noexcept;
// remove copy constructor
Foo(const Foo &) = delete;
// delete assignment operator
Foo &operator=(const Foo &) = delete;
size_t size();
};
main.cpp
#include <iostream>
#include "main.h"
Foo::Foo(size_t len) : big(len) {}
Foo::Foo(Foo&& other) noexcept : big(std::move(other.big)) {}
size_t Foo::size() { return this->big.size(); }
int main() {
Foo ms(1000); // on the stack
ms.big[0] = 42;
auto mh = new Foo(std::move(ms)); // on the heap (no copy?)
std::cout << mh->size() << ", " << mh->big[0] << std::endl;
delete mh;
}
【问题讨论】:
-
如果您
= delete复制构造函数和复制赋值运算符,您不必担心会生成秘密副本。如果发生这种情况,编译器会报错。 -
如果您提供移动构造函数,您可能需要提供移动赋值运算符。这是3/5/0 规则的一部分。虽然在这种情况下你可以只使用编译器提供的。
-
big中的数据一开始就不会在堆栈中。当然,堆栈上的部分会被复制。我不太确定这里有什么不清楚的地方。 -
@BrunoGrieder 如果
Foo没有被复制,那么它也不是成员。 -
@FedericoklezCulloca 也许对于某些类型,例如
std::array,但对于大多数容器,它会复制该容器的内部状态(例如指向数据和大小的指针)并将原始容器清零。实际数据保留在原处。编辑:即使对于像std::array这样难以移动的容器,它也会移动每个元素,因此例如移动std::vector的std::array仍然不仅仅是复制/清除。