2013-09-01 4 views
3

저는 C++ 이동 기능을 간신히 사용했기 때문에 내가하고있는 일이 정확하다고 확신하지 못합니다. 내 코드를 살펴보고 내가 작성한 실수를 지적 해 주시면 감사하겠습니다.이 방법은 이동 참조와 unique_ptr을 사용하는 올바른 방법입니까?

아이디어는 키에 의해 저장된 리소스 맵을 만드는 것입니다. 자원은 복사 할 수없고 움직일 수 없습니다.

또한 클래스에는 생성자 및 소멸자 정의가 필요합니까?

감사합니다.

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

, 고유의 포인터를 전달

#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(); 
} 

답변

3

여기 상황의 핵심을 설명하는 방법과 관용구 코드를 작성하는 코드의 간단한 조각이다 (또는 다른 모든 이동 전용 형식)을 으로 바꿔서 이동하십시오. 당신이 객체 조건부의 소유권을 가져올 때 내가 만난


한 특별한 상황입니다. 이 경우, 참조에 의해 고유의 포인터를 전달하고 나중에 그것을 검사 :

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); 
} 
+0

함수를 호출 한 사용자가 명시 적으로 객체를 내 value 매개 변수로 이동해야합니까? –

+1

@NeilKirk : 발신자가 lvalue를 가지고 있으면 yes입니다. 그렇지 않으면 암시 적이며 추가 코드가 필요하지 않습니다 (첫 번째 사용 예 에서처럼). 그리고이 예제는'add_to_map (std :: make_unique (1,2,3)); '이어야합니다. 실제로 C++ 14가 필요합니다. –

+0

Release 함수의 반환 유형은 어떻습니까? –

관련 문제