3

私は 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();
}
4

1 に答える 1

3

これは、状況の核心とコードを慣用的に記述する方法を示す単純化されたコードです。

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));

基本的に、一意のポインター (またはその他の可動のみの型) をで渡し、そこから移動します。


私が遭遇した特別な状況の 1 つは、条件付きでオブジェクトの所有権を取得したい場合です。その場合、参照によって一意のポインターを渡し、後で検査します。

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);
}
于 2013-09-01T16:51:27.927 に答える