C++ unique_ptr和map

Mat*_*ner 24 c++ gcc stl unique-ptr c++11

我正在尝试使用C++ 0x unique_ptr,map如下所示:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

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

main.cpp:19:   instantiated from here
/usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘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: error: used here

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

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

sel*_*tze 27

第一:你的类Foo实际上是std :: string的非常差的近似值.我预测会有很多内存泄漏.(搜索"三规则".)

第二:指针不能隐式转换为unique_ptr对象(出于安全原因).但是模板化对构造函数要求参数可以隐式转换为相应的值类型.海湾合作委员会似乎允许这样,但这是一个错误.您必须手动创建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;
}
Run Code Online (Sandbox Code Playgroud)

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

auto a = bar.emplace(1,make_unique<Foo>("one"));
Run Code Online (Sandbox Code Playgroud)

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

您目击的实际问题是,对构造函数尝试复制unique_ptr,即使这样的对象只是"可移动".似乎GCC的C++ 0x支持还不足以正确处理这种情况.据我所知,我上面的线应该按照现行标准草案(N3126)运作.

编辑:我刚尝试以下作为在实验C++ 0x模式下使用GCC 4.5.1的变通方法:

map<int,unique_ptr<int> > themap;
themap[42].reset(new int(1729));
Run Code Online (Sandbox Code Playgroud)

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

  • 不幸的是,这不适用于GCC 4.4.3或4.5.0. (3认同)

Mat*_*ner 6

我不相信这是可能的正确使用unique_ptrmap::insert呢.这是GCC的错误:

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

对于GCC 4.6来说,它看起来可能是固定的,但它不会在SVU上为vanilla Ubuntu 10.04.1构建来确认.

Update0

这不适用于GCC svn r165422(4.6.0).