c ++ std :: unique_ptr不会在地图中编译 [英] c++ std::unique_ptr won't compile in map

查看:1352
本文介绍了c ++ std :: unique_ptr不会在地图中编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正试图在std :: unordered_map中存储std :: unique_ptr,但我得到一个奇怪的编译错误。
相关代码:

I'm currently trying to store a std::unique_ptr in a std::unordered_map, but I get a weird compile error. Relevant code:

#pragma once

#include "Entity.h"

#include <map>
#include <memory>

class EntityManager {
private:
    typedef std::unique_ptr<Entity> EntityPtr;
    typedef std::map<int, EntityPtr> EntityMap;

    EntityMap map;
public:

    /*
    Adds an Entity
    */
    void addEntity(EntityPtr);

    /*
    Removes an Entity by its ID
    */
    void removeEntity(int id) {
        map.erase(id);
    }

    Entity& getById(int id) {
        return *map[id];
    }
};

void EntityManager::addEntity(EntityPtr entity) {
    if (!entity.get()) {
        return;
    }

    map.insert(EntityMap::value_type(entity->getId(), std::move(entity)));
}

这是编译错误:

c:\program files (x86)\microsoft visual studio 12.0\vc\include\tuple(438): error C2280: 'std::unique_ptr<Entity,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
1>          with
1>          [
1>              _Ty=Entity
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(1486) : see declaration of 'std::unique_ptr<Entity,std::default_delete<_Ty>>::unique_ptr'
1>          with
1>          [
1>              _Ty=Entity
1>          ]
1>          This diagnostic occurred in the compiler generated function 'std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)'
1>          with
1>          [
1>              _Kty=int
1>  ,            _Ty=EntityManager::EntityPtr
1>          ]


推荐答案

错误是因为代码中的某处想要复制 std :: pair< int,std :: unique_ptr< Entity>> ,但是没有复制构造函数能够这样,因为unique_ptr的不可复制。这是特别不可能防止拥有同一内存的多个指针。

The error is because somewhere in the code, map wants to copy a std::pair<int, std::unique_ptr<Entity>>, however there is no copy constructor capable of this, because unique_ptr's are not copy constructable. This is specifically impossible to prevent multiple pointers owning the same memory.

因此在std :: move之前,没有办法使用不可复制的元素。

So before std::move, there was no way to use an uncopiable element.

有一些解决方案这里

然而,在c ++ 11中Map可以使用std :: move使用不可复制的值。

However, in c++11 Map can make use of std::move to work with non-copyable values.

这是通过提供另一个插入运算符完成的,该插入运算符重载以包括此签名:

This is done by providing another insert operator, which is overloaded to include this signature:

template< class P > std::pair<iterator,bool> insert( P&& value );

这意味着可以转换为value_type的类的右值可以用作参数。旧插入仍然可用:

This means an rvalue of a class that can be turned into a value_type can be used as an argument. The old insert is still available:

std::pair<iterator,bool> insert( const value_type& value );

此插入实际上复制一个value_type,这将导致一个错误,因为value_type不是可复制的。

This insert actually copies a value_type, which would cause an error since value_type is not copy constructable.

我认为编译器选择非模板的重载,这会导致编译错误。因为它不是一个模板,它的失败是一个错误。至少在gcc上,使用std :: move的另一个插入是有效的。

I think the compiler is selecting the non-templated overload, which causes the compilation error. Because it is not a template, it's failure is an error. On gcc at least, the other insert, which uses std::move, is valid.

这里是测试代码,看看你的编译器是否支持正确: p>

Here is test code to see if your compiler is supporting this correctly:

#include <iostream>
#include <memory>
#include <utility>
#include <type_traits>

class Foo {
};

using namespace std;

int main() {
    cout << is_constructible<pair<const int,unique_ptr<Foo> >, pair<const int,unique_ptr<Foo> >& >::value << '\n';
    cout << is_constructible<pair<const int,unique_ptr<Foo> >, pair<const int,unique_ptr<Foo> >&& >::value << '\n';
}

第一行将输出0,因为拷贝构造无效。

The first line will output 0, because copy construction is invalid. The second line will output 1 since the move construction is valid.

此代码:

map.insert(std::move(EntityMap::value_type(entity->getId(), std::move(entity))));

应调用move insert重载。

should call the move insert overload.

This code:

This code:

map.insert<EntityMap::value_type>(EntityMap::value_type(entity->getId(), std::move(entity))));

真的应该叫它。

:神秘继续,vc返回不正确的11为测试...

the mystery continues, vc returns the incorrect 11 for the test...

这篇关于c ++ std :: unique_ptr不会在地图中编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆