提问人:Mohammad Hussein 提问时间:7/9/2021 最后编辑:Mohammad Hussein 更新时间:7/9/2021 访问量:362
如何在 c++ 中移动对象而不是复制它?
How to move an object instead of copying it in c++?
问:
有没有办法让我移动在 main 中创建的对象 GuitarSpec,而不是复制它?
所以这里是以下示例:- 有一个 Inventory 类,它有一个吉他列表,要添加吉他,有一个名为 addGuitar 的函数,它将 string、double 和 GuitarSpec 对象作为参数。
库存
class Inventory {
private:
list<Guitar> inventory;
public:
void addGuitar(const string &, double, const GuitarSpec &spec);
addGuitar 函数
void Inventory::addGuitar(const string &serialNumber, double price,
const GuitarSpec &spec) {
inventory.emplace_back(serialNumber, price, spec);
}
Guitar 构造函数
Guitar::Guitar(const string& serialNumber, double price, const GuitarSpec &spec)
: serialNumber{serialNumber}, price{price}, spec(spec) {
cout << "Guitar Constructor" << endl;
}
主要功能:-
Inventory inventory;
inventory.addGuitar(
"1001", 200,
GuitarSpec(toString(FEDER), "starocaster", toString(ELECTRIC),
toString(Wood::SIKTA), toString(Wood::SIKTA)));
有没有办法移动该 GuitarSpec 对象而不是获取它的副本,或任何其他更好的解决方案?
答:
1赞
Swift - Friday Pie
7/9/2021
#1
当您考虑只移动一个参数时,您可能会避免声明函数重载,其中之一就是从临时参数移动。或者你有使用临时物的设计,那么你为什么不遵循“放置”策略,在现场创建新对象呢?
但是,如果移动了两个或多个参数,则所需的重载数将为 4 个、8 个,依此类推。这不好,在这种情况下,完美的前锋可能更有用。以 C++11 样式转发单个参数(类型)的示例:Spec
#include <iostream>
#include <utility>
struct Data {
Data(const Data&) { std::cout << "Data copied\n"; }
Data() { std::cout << "Data created\n"; }
};
struct Spec {
Data *ptr;
Spec() : ptr(new Data()) {};
Spec(const Spec& other) : ptr(new Data{*other.ptr}) {};
Spec(Spec && other) : ptr(other.ptr) {
other.ptr = nullptr;
std::cout << "Data moved\n";
}
Spec& operator=(const Spec& other) { ptr = new Data{*other.ptr};
std::cout << "Data copied\n";
return *this; }
Spec& operator=(Spec&& other) { ptr = other.ptr; other.ptr = nullptr;
std::cout << "Data moved\n"; return *this;
}
~Spec() { delete ptr; }
};
struct foo {
Spec d;
template < typename T, std::enable_if_t<std::is_convertible<T, Spec>::value> * = nullptr>
foo(T&& v) : d(std::forward<T>(v)) { }
template <typename T>
auto set_spec(T&& v) -> decltype(v = std::forward<Spec>(v), void())
{ d = std::forward<T>(v); }
};
int main()
{
std::cout << "Move\n";
foo a {Spec()};
a.set_spec(Spec());
std::cout << "Copy\n";
Spec s;
foo b {s};
a.set_spec(s);
}
您必须修改整个责任链才能使用它,从重载 Inventory 的方法开始:
void addGuitar(const string &serialNumber, double price, GuitarSpec&& spec) {
// move, do we want move string?
inventory.emplace_back(serialNumber, price, std::move(spec));
}
或者使用完美转发,此模板可以在适当的时候复制或移动(例如没有 SFINAE):
template <class SN, class SP>
void addGuitar(SN&& serialNumber, double price, SP&& spec)
{
inventory.emplace_back(std::forward<std::string>(serialNumber),
price, std::forward<GuitarSpec>(spec));
}
从技术上讲,可能只是如果我们不想费心通过 SFINAE 限制接口,假设我们总是正确地使用它,并且如果它不是公共接口,则不会发生任何错误(Murphy,放下你的手)。在具有长寿命和多个开发人员的大型项目中,这是一个糟糕的假设。addGuitar
评论
std::vector
std::list
GuitarSpec
GuitarSpec&&
std::move
Guitar