适当的破坏者/RAII/Something

Proper Destructors / RAII / Something

本文关键字:RAII Something 破坏者      更新时间:2023-10-16

下面是一个我遇到的问题的最小例子,我不知道该如何解决它:

#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>());
}