适当的析构函数/ RAII / Something

时间:2014-05-27 07:01:17

标签: c++

这是我遇到的一个问题的最小例子,我无法弄清楚应该如何解决它:

#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,segfaults并吐出的时候没有问题:

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));

4 个答案:

答案 0 :(得分:6)

std::unique_ptr正在尝试删除堆栈分配的Thing实例。

您的错误基本上在以下几行:

 Thing thing;
 app.add_thing(&thing);

答案 1 :(得分:1)

您应该将本地对象传递给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获取指针指针的所有权将被尝试释放超过1次。

答案 2 :(得分:1)

add_thing的界面错误,因为它需要&#34;非拥有&#34;指向Thing的原始指针然后假设它可以通过从中构造unique_ptr来获取传入的对象的完全所有权。

如果您将add_thing更改为按值unique_ptr<Thing>,则会阻止调用者隐式转换原始指针,并且不会需要构造新的unique_ptr堆分配到add_thing函数中。

e.g。

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)现在可以使用。)

答案 3 :(得分:0)

您未正确转让所有权。您可以使用带有自定义删除器的共享指针来防止删除引用的变量:

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