24

我正在尝试在这样的内部使用C++0x unique_ptrmap

// compile with `g++ main.cpp -std=gnu++0x`

#include <string.h>    
#include <map>
#include <memory>

using namespace std;

struct Foo {
    char *str;    
    Foo(char const *str_): str(strdup(str_)) {}
};

int main(void) {
    typedef std::map<int, unique_ptr<Foo>> Bar;
    Bar bar;
    auto a = bar.insert(Bar::value_type(1, new Foo("one")));
    return 0;
}

但是 GCC 给了我以下错误(缩短,我认为这是相关部分,请在您自己的 C++ 编译器上测试):

main.cpp:19:从这里实例化
/usr/include/c++/4.4/bits/unique_ptr.h:214: 错误:删除函数'std::unique_ptr::unique_ptr(const std::unique_ptr&) [with _Tp = Foo, _Tp_Deleter = std::default_delete]'
/usr/include/c++/4.4/bits/stl_pair.h:68:错误:在这里使用

我真的不确定我做错了什么,这适用于 MSVC。我发现了非常相似的问题,看起来很相似,但是他们的解决方案对我不起作用。

matt@stanley:/media/data/src/c++0x-test$ gcc --version
gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3
4

4 回答 4

28

第一:你的类 Foo 真的是一个非常糟糕的 std::string 近似值。我预测会有很多内存泄漏。(搜索“三法则”。)

第二:指针不能隐式转换为 unique_ptr 对象(出于安全原因)。但是模板对构造函数要求参数可以隐式转换为相应的值类型。GCC 似乎允许这样做,但这是一个错误。您必须手动创建 unique_ptr 对象。不幸的是,C++0x 草案缺少以下非常有用的函数模板,可以简化临时 unique_ptr 对象的创建。它也是异常安全的:

template<class T, class...Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    std::unique_ptr<T> ret (new T(std::forward<Args>(args)...));
    return ret;
}

此外,让我们使用新的emplace函数而不是insert

auto a = bar.emplace(1,make_unique<Foo>("one"));

emplace将两个参数转发给相应的对构造函数。

您目睹的实际问题是 pair 构造函数试图复制一个 unique_ptr,即使这样的对象只是“可移动的”。似乎 GCC 的 C++0x 支持还不足以正确处理这种情况。据我所知,我上面的线路应该按照当前的标准草案(N3126)工作。

编辑:我刚刚在实验性 C++0x 模式下使用 GCC 4.5.1 尝试了以下解决方法:

map<int,unique_ptr<int> > themap;
themap[42].reset(new int(1729));

这也应该适用于即将发布的标准,但 GCC 也拒绝它。看起来您必须等待 GCC 在地图和多地图中支持 unique_ptr。

于 2010-10-11T13:31:57.603 回答
6

我不相信现在可以正确unique_ptr使用map::insert。这是它的 GCC 错误:

错误 44436 - [C++0x]在关联容器和无序容器中实现insert(&&)emplace*

看起来它可能已针对 GCC 4.6 修复,但它不会在 vanilla Ubuntu 10.04.1 上从 SVN 构建来确认。

更新0

从 GCC svn r165422 (4.6.0) 开始,这不起作用。

于 2010-10-12T15:19:40.823 回答
1

我刚刚在 gcc 4.6.0 中修改了 unique_ptr。这是一些正常工作的(非常丑陋的)代码:

std::map<int, std::unique_ptr<int> > table;
table.insert(std::pair<int, std::unique_ptr<int>>(15, std::unique_ptr<int>(new int(42))));
table[2] = std::move(table[15]);
for (auto& i : table)
{
    if (i.second.get())
        printf("%d\n", *i.second);
    else
    {
        printf("empty\n");
        i.second.reset(new int(12));
    }
}
printf("%d\n", *table[15]);

输出为 42,空,12 - 显然它有效。据我所知,唯一的“问题”是那个看起来很糟糕的插入命令。'emplace' 未在 gcc 4.6.0 中实现

于 2011-06-01T03:12:07.030 回答
0

尝试使用emplace地图的方法。

于 2017-12-30T04:19:11.477 回答