这是使用移动引用和unique_ptr的正确方式吗
Is this the correct way to use move references and unique_ptr?
我几乎没有使用过C++移动功能,所以我不相信我所做的是正确的。如果有人仔细查看我的代码并指出我所犯的任何错误,我将不胜感激。
这个想法是创建一个按键存储的资源映射。资源可能是不可复制和不可移动的。
另外,我的类是否需要构造函数和析构函数定义?
谢谢。
#define TYPE(x) std::identity<decltype(x)>::type
namespace General
{
template<class T>
std::string ToString(const T& x)
{
std::ostringstream ss;
ss << x;
return ss.str();
}
}
namespace General
{
template<class T, class KEY = std::string>
class ResourceManager
{
public:
typedef T ResourceType;
typedef KEY KeyType;
void Load(const KeyType& key, std::unique_ptr<ResourceType>&& resource);
const ResourceType& Read(const KeyType& key) const;
ResourceType& Modify(const KeyType& key);
void Unload(const KeyType& key);
std::unique_ptr<ResourceType>&& Release(const KeyType& key);
void UnloadAll();
private:
std::map<KeyType, std::unique_ptr<ResourceType>> data;
};
}
template<class T, class KEY>
void General::ResourceManager<T, KEY>::Load(const KeyType& key, std::unique_ptr<ResourceType>&& resource)
{
auto find_it = data.lower_bound(key);
if (find_it != data.end() && ! (data.key_comp()(key, find_it->first)))
{
throw std::runtime_error(General::ToString(key) + " already exists!");
}
else
{
data.insert(find_it, TYPE(data)::value_type(key, std::move(resource)));
}
}
template<class T, class KEY>
const typename General::ResourceManager<T, KEY>::ResourceType& General::ResourceManager<T, KEY>::Read(const KeyType& key) const
{
auto find_it = data.find(key);
if (find_it == data.end())
{
throw std::runtime_error(General::ToString(key) + " could not be found!");
}
else
{
return *find_it->second;
}
}
template<class T, class KEY>
typename General::ResourceManager<T, KEY>::ResourceType& General::ResourceManager<T, KEY>::Modify(const KeyType& key)
{
auto find_it = data.find(key);
if (find_it == data.end())
{
throw std::runtime_error(General::ToString(key) + " could not be found!");
}
else
{
return *find_it->second;
}
}
template<class T, class KEY>
void General::ResourceManager<T, KEY>::Unload(const KeyType& key)
{
auto find_it = data.find(key);
if (find_it == data.end())
{
throw std::runtime_error(General::ToString(key) + " could not be found!");
}
else
{
data.erase(find_it);
}
}
template<class T, class KEY>
std::unique_ptr<typename General::ResourceManager<T, KEY>::ResourceType>&& General::ResourceManager<T, KEY>::Release(const KeyType& key)
{
auto find_it = data.find(key);
if (find_it == data.end())
{
throw std::runtime_error(General::ToString(key) + " could not be found!");
}
else
{
auto resource = std::move(find_it->second);
data.erase(find_it);
return std::move(resource);
}
}
template<class T, class KEY>
void General::ResourceManager<T, KEY>::UnloadAll()
{
data.clear();
}
下面是一段简化的代码,它演示了您的情况的关键以及如何习惯地编写代码:
std::map<int, std::unique_ptr<Foo>> m;
void add_to_map(int key, std::unique_ptr<Foo> val)
{
m[key] = std::move(val);
}
用法:
add_to_map(1, std::unique_ptr<Foo>(new Foo(1, 2, 3)));
std::unique_ptr<Foo> p(new Foo(true, 'x'));
p->mutate();
add_to_map(std::move(p));
基本上,通过值传递唯一指针(或任何其他仅可移动类型),然后从中移动。
我遇到的一种特殊情况是,当您想要有条件地获得对象的所有权时。在这种情况下,通过引用传递唯一指针,然后对其进行检查:
void add_maybe(std::unique_ptr<Foo> & val)
{
if (rand() % 2 == 0)
{
m[12] = std::move(val);
}
}
用法:
std::unique_ptr<Foo> p(new Foo(true, 'x'));
add_maybe(p);
if (p) { /* we still own the resource */ }
else { /* the resource is now owned by the map */ }
更新:要从地图中释放对象,请按值返回:
std::unique_ptr<Foo> release(int key)
{
auto it = m.find(key);
return it == m.end() ? { } : std::move(it->second);
}
相关文章:
- 编译器会秘密增加结构的对齐方式吗?
- 确定范围是访问虚拟功能的合法方式吗?
- 有什么优雅的方式吗?(类型参数包)
- Qt:对于生产者-消费者模式中的消费者来说,这是正确的退出方式吗
- 常量标识符在C++中有不同的处理方式吗
- C ++变量赋值,这是正常的方式吗
- 有清除类型的快捷方式吗
- Qt信号槽在线程上,这是安全的方式吗?
- 这是使用移动引用和unique_ptr的正确方式吗
- 这是从singleton类派生的标准方式吗
- 这是访问类的数据成员的正确方式吗
- c++ Mixins——这是正确的实现方式吗?
- 部分类专门化只是编写完全专门化的另一种方式吗?
- 这是在c++中启动线程的正确方式吗?
- OPEN GL:这是使用VBO、IBO和VAO的正确方式吗?
- 这是在c++中运行循环的有效方式吗?
- 枚举是实现位标志的规范方式吗?
- 在cuda中有更好/更干净/更优雅的malloc和free方式吗?
- c++应用程序有标准的数据存储方式吗?
- 这是访问列表中对象的正确方式吗