【问题标题】:Proper Destructors / RAII / Something适当的析构函数 / RAII / 某事
【发布时间】:2014-07-15 23:40:57
【问题描述】:

这是我遇到的问题的一个最小示例,但我不知道应该如何解决它:

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

【问题讨论】:

标签: c++


【解决方案1】:

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

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

 Thing thing;
 app.add_thing(&thing);

【讨论】:

    【解决方案2】:

    您应该将本地对象传递给 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 次。

    【讨论】:

    • @Bathsheba:但即使使用这种解决方案,add_thing 的接口也是危险的,因为它不能防止这种客户端“错误”或以任何方式记录这种用法存在问题。跨度>
    • 啊。好的。我之前尝试初始化它们的原因是因为在添加它们之前我试图在它们上运行一些其他方法。我想我只需要先添加它们,然后在向量的最后一个元素上运行方法?
    • 是的,我应该写“一个可能的解决方案”,但我现在就离开它,因为它会使更多有用的 cmets 失效。
    • @CharlesBailey 你说得对,界面很危险,让我们做一些讨厌的事情。
    【解决方案3】:

    add_thing 的接口是错误的,因为它需要一个指向 Thing 的“非拥有”原始指针,然后 假定它可以通过构造来自它的unique_ptr

    如果您将add_thing 更改为按值获取unique_ptr&lt;Thing&gt;,则调用者将无法隐式转换原始指针,并且不需要将新的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&lt;Thing&gt;(new Thing) 现在可以使用。)

    【讨论】:

    • unique_ptr 的替代方法是将Thing &amp;&amp; 传递给moveunique_ptr
    • 好的,我会调查的。我最初有,但是必须事先手动创建 unique_ptrs 相当笨拙
    • @nwp 两个 & 会做什么?
    • @nwp:这可行,但也需要Thing 是可移动的。
    • @Jagoly A Test &amp;&amp; 是一个临时值 (rvalue)。当使用堆栈中的值时,你会得到一个编译器错误,说它不能将左值转换为右值,从而防止了这种错误。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2014-07-06
      • 1970-01-01
      • 2016-07-21
      • 1970-01-01
      • 1970-01-01
      • 2012-07-24
      • 2013-10-01
      • 2012-02-25
      • 2013-01-20
      相关资源
      最近更新 更多