将不可复制的对象放入std容器中
Putting non-copyable objects into std-containers
这个类是否设计为标准的c++ 0x方式来防止复制和赋值,以保护客户端代码免受意外的双重删除data
?
struct DataHolder {
int *data; // dangerous resource
DataHolder(const char* fn); // load from file or so
DataHolder(const char* fn, size_t len); // *from answers: added*
~DataHolder() { delete[] data; }
// prevent copy, to prevent double-deletion
DataHolder(const DataHolder&) = delete;
DataHolder& operator=(const DataHolder&) = delete;
// enable stealing
DataHolder(DataHolder &&other) {
data=other.data; other.data=nullptr;
}
DataHolder& operator=(DataHolder &&other) {
if(&other!=this) { data = other.data; other.data=nullptr};
return *this;
}
};
你注意到,我在这里定义了新的move和move-assign方法。我是否正确地实现了它们?是否有任何方法我可以-与移动和移动分配定义-把DataHolder
在一个标准的容器?比如vector
?我该怎么做呢?
我想知道,我想到了一些选项:
// init-list. do they copy? or do they move?
// *from answers: compile-error, init-list is const, can nor move from there*
vector<DataHolder> abc { DataHolder("a"), DataHolder("b"), DataHolder("c") };
// pushing temp-objects.
vector<DataHolder> xyz;
xyz.push_back( DataHolder("x") );
// *from answers: emplace uses perfect argument forwarding*
xyz.emplace_back( "z", 1 );
// pushing a regular object, probably copies, right?
DataHolder y("y");
xyz.push_back( y ); // *from anwers: this copies, thus compile error.*
// pushing a regular object, explicit stealing?
xyz.push_back( move(y) );
// or is this what emplace is for?
xyz.emplace_back( y ); // *from answers: works, but nonsense here*
emplace_back
的想法只是一个猜测,在这里。
编辑:为了方便读者,我将答案放入示例代码中。
你的示例代码看起来大部分是正确的。
if(&other!=this)
在你的移动赋值操作符看起来不必要,但无害。初始化列表向量构造函数不能工作。这将尝试复制你的
DataHolder
,你应该得到一个编译时错误。带右值参数的push_back和emplace_back调用可以工作。使用左值参数(使用
y
)会给你编译时错误。
push_back和emplace_back在使用方式上没有区别。emplace_back适用于不想在vector之外构造DataHolder,而是传递参数仅在vector内部构造DataHolder的情况。例如:
// Imagine this new constructor:
DataHolder(const char* fn, size_t len);
xyz.emplace_back( "data", 4 ); // ok
xyz.push_back("data", 4 ); // compile time error
更新:
我刚刚注意到你的移动赋值操作符有内存泄漏。
DataHolder& operator=(DataHolder &&other)
{
if(&other!=this)
{
delete[] data; // insert this
data = other.data;
other.data=nullptr;
}
return *this;
}
没有名称的临时对象,例如:DataHolder("a")
,可用时移动。c++ 0x中的标准容器总是在可能的情况下移动,这也允许std::unique_ptr
被放入标准容器中。
除此之外,你实现了你的移动操作错误:
// enable stealing
DataHolder(const DataHolder &&other) {
data=other.data; other.data=nullptr;
}
DataHolder& operator=(const DataHolder&&other) {
if(&other!=this) { data = other.data; other.data=nullptr};
return *this;
}
如何从一个常量对象移动?你不能把other
改成data
,因为other
是不变的。把它改成简单的DataHolder&&
相关文章:
- 可组合的lambda/std::函数与std::可选
- 简单可复制与可简单复制
- std::可选实现为联合与字符[]/aligned_storage
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 如何使用 CUDA 将 std::vector<std::string> 复制到 GPU 设备
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 可变参数宏:无法通过"..."传递非平凡可复制类型的对象
- 为什么移动 std::可选不重置状态
- std::可选::value_or()-惰性参数求值
- 为什么 std::atomic<std::string> 会给出微不足道的可复制错误?
- 用于比较基元类型的std::可选的有趣程序集
- 我可以隐式地创建一个琐碎的可复制类型吗
- 是std::memcpy在不同的可复制类型之间的未定义行为
- 防御性地应用 std::move 到平凡可复制的类型是否不可取
- 为什么 std::function 本身是可复制构造的类型?
- 交换包含非一般可复制类型的“std::aligned_storage”实例-未定义的行为
- 使用 std::string 参数和不可移动/可复制参数构建 std::map
- 将std::memcpy用于非平凡可复制类型的对象
- std::unordered_map<T,std::unique_ptr<U>>可复制吗?海湾合作委员会错误?
- 一个普通的可复制的::std::元组类模板可能吗?是否存在实现