适当的破坏者/RAII/Something
Proper Destructors / RAII / Something
下面是一个我遇到的问题的最小例子,我不知道该如何解决它:
#include <vector>
#include <memory>
class Thing {
};
class App {
public:
std::vector<std::unique_ptr<Thing>> thingVec;
void add_thing(Thing*);
};
void App::add_thing(Thing* thing) {
thingVec.push_back(std::unique_ptr<Thing>(thing));
}
int main() {
App app;
Thing thing;
app.add_thing(&thing);
}
然而,当到达main、segfault和spitsout:的末尾时,它编译和运行没有任何问题
Error in `/path/testapp': free(): invalid pointer: 0x00007fff97118070 ***
有什么可能的帮助吗?我想要存储(唯一的(指针的原因是Thing通常是派生的。
编辑:一个可行的解决方案:
#include <vector>
#include <memory>
class Thing {
};
class App {
public:
std::vector<std::unique_ptr<Thing>> thingVec;
void add_thing(Thing*);
};
void App::add_thing(Thing* thing) {
thingVec.push_back(std::unique_ptr<Thing>(thing));
}
int main() {
App app;
Thing* thing = new Thing;
app.add_thing(thing);
}
但据我所知,我应该能够完全避免使用new,而使用make_unique?不过,我似乎找不到make_unique的实际定义。
编辑2:
这样更合适吗?有没有一种看起来不那么凌乱的方法可以做到这一点?除此之外,它运行良好。
#include <vector>
#include <memory>
#include <iostream>
class Thing {
public:
int foo = 42;
};
class App {
public:
std::vector<std::unique_ptr<Thing>> thingVec;
void add_thing(std::unique_ptr<Thing>);
};
void App::add_thing(std::unique_ptr<Thing> thing) {
thingVec.push_back(std::move(thing));
}
int main() {
App app;
app.add_thing(std::unique_ptr<Thing>(new Thing()));
std::cout << app.thingVec.back()->foo << std::endl;
}
因为我可能会遇到像这样的线路
app.thingVex.back()->barVec.back()->blahMap.emplace("flop", std::unique_ptr<Tree>(new Tree));
std::unique_ptr
正试图删除堆栈分配的Thing
实例。
你的错误主要在以下几行:
Thing thing;
app.add_thing(&thing);
add_thing
的接口是错误的,因为它使用了一个指向Thing
的"非拥有"原始指针,然后假设可以通过从中构造unique_ptr
来获得传入对象的完全所有权。
如果将add_thing
更改为按值取unique_ptr<Thing>
,则将阻止调用方隐式转换原始指针,并且不需要将新的unique_ptr
构造为add_thing
函数中的堆分配对象。
例如
void App::add_thing(std::unique_ptr<Thing> thing) {
thingVec.push_back(std::move(thing));
}
int main() {
App app;
app.add_thing(std::make_unique<Thing>());
}
(请注意,std::make_unique
是未来的功能;std::unique_ptr<Thing>(new Thing)
现在可以工作。(
您应该将本地对象传递给unique_ptr。
更换
Thing thing;
app.add_thing(&thing);
带有
app.add_thing(new Thing);
如果您还想编辑对象
Thing *thing = new Thing;
// thing->some_val = val;
app.add_thing(thing);
请确保不要在应用程序中添加两次相同的对象,因为std::unique_ptr获取指针指针的所有权会尝试释放一次以上。
您未正确转移所有权。您可以使用带有自定义deleter的共享指针来防止删除引用的变量:
#include <vector>
#include <memory>
class Thing {
};
class App {
public:
std::vector<std::shared_ptr<Thing>> thingVec;
void add_thing(std::shared_ptr<Thing>&& thing) {
thingVec.push_back(std::move(thing));
}
};
template<typename T>
inline std::shared_ptr<T> make_no_delete(T& value)
{
return std::shared_ptr<T>(&value, [](void*){});
}
int main() {
App app;
Thing thing;
// Add without transferring ownership:
app.add_thing(make_no_delete(thing));
// Add and transfer ownership:
app.add_thing(std::make_shared<Thing>());
}
相关文章:
- 具有瞬态资源的RAII类
- 使用RAII在给定次数的迭代后重新分配资源
- 在文件夹迭代上实现 RAII
- 在 RAII 构造中修改 RVO 值是否安全?
- RAII 等效于 FIFO 发布订单
- 为什么标准首选圆括号初始化为"make_<something>"?
- 当无法进行RAII时,如何在C++中"try/finally"?
- 如何处理 RAII 中的资源等待
- c++重载=运算符,RAII
- 如何使用 RAII 包装返回错误代码的 C 分配
- 使用 RAII 替换最终块以释放内存
- C++,当函子不是一个选项时,我如何编写带有自定义函数调用的模板化 RAII 包装器?
- 返回持有 std::mutex 锁的 RAII 容器类
- 继承、后台线程和 RAII
- 将 C 包装在 RAII 中而不公开类型
- 避免在构造函数中分配或保持简单性(和 RAII?
- 避免 RAII 计时器对象中的虚假构造和破坏
- 什么是使用something::something:something mean(c++)
- Raii vs.垃圾收集器
- 适当的破坏者/RAII/Something