Tip*_*s48 7 c++ unique-ptr c++11 visual-studio-2012
我目前正在尝试将std :: unique_ptr存储在std :: unordered_map中,但是我得到了一个奇怪的编译错误.相关代码:
#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)));
}
Run Code Online (Sandbox Code Playgroud)
这是编译错误:
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> ]
Run Code Online (Sandbox Code Playgroud)
错误是因为代码中的某个地方,map想要复制a std::pair<int, std::unique_ptr<Entity>>,但是没有复制构造函数可以做到这一点,因为unique_ptr不是可复制构造的.这对于防止具有相同存储器的多个指针是特别不可能的.
所以在std :: move之前,没有办法使用不可复制的元素.
有一些解决方案在这里.
但是,在c ++ 11中,Map可以使用std :: move来处理不可复制的值.
这是通过提供另一个插入操作符来完成的,该操作符被重载以包含此签名:
template< class P > std::pair<iterator,bool> insert( P&& value );
Run Code Online (Sandbox Code Playgroud)
这意味着可以转换为value_type的类的rvalue可以用作参数.旧插件仍然可用:
std::pair<iterator,bool> insert( const value_type& value );
Run Code Online (Sandbox Code Playgroud)
此插入实际上复制了一个value_type,这会导致错误,因为value_type不是可复制构造的.
我认为编译器正在选择非模板化的重载,这会导致编译错误.因为它不是模板,所以它的失败是一个错误.至少在gcc上,另一个使用std :: move的插入是有效的.
这是测试代码,看看你的编译器是否正确支持这个:
#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';
}
Run Code Online (Sandbox Code Playgroud)
第一行将输出0,因为复制构造无效.第二行输出1,因为移动结构是有效的.
这段代码:
map.insert(std::move(EntityMap::value_type(entity->getId(), std::move(entity))));
Run Code Online (Sandbox Code Playgroud)
应该调用移动插入过载.
这段代码:
map.insert<EntityMap::value_type>(EntityMap::value_type(entity->getId(), std::move(entity))));
Run Code Online (Sandbox Code Playgroud)
真的应该叫它.
编辑:神秘感继续,vc返回错误的11测试...
您的代码适用于以下内容:
int main() {
EntityManager em;
em.addEntity(std::unique_ptr<Entity>(new Entity(1)));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,这很麻烦,我建议像这样定义 addEntity :
void EntityManager::addEntity(Entity *entity) {
if (entity == nullptr)
return;
}
map.insert(EntityMap::value_type(entity->getId(),
std::unique_ptr<Entity>(entity)));
}
Run Code Online (Sandbox Code Playgroud)
并插入
em.addEntity(new Entity(...));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9569 次 |
| 最近记录: |