2010-09-23 3 views
3

Если мой класс SomeType есть метод, который возвращает элемент из карты (с помощью ключа) говоритВозвращение unique_ptr из метода класса C++ 0x

std::unique_ptr<OtherType> get_othertype(std::string name) 
{ 
    return otMap.find(name); 
} 

, что бы идти на пользу абонент будет Получать указатель на карту, а не на копию? Можно ли это сделать или попытаться вызвать конструктор копирования (и не удалиться, поскольку он был удален), потому что он возвращается?

Предполагая, что я должен использовать unique_ptr в качестве элементов моей карты.

UPDATE ::

После попытки реализовать код, кажется, что unique_ptr и станд: отображение /: пара не работают вместе в GCC 4.4.4, пара как раз не нравится unique_ptr в качестве параметра типа. (см. Can't create map of MoveConstructibles).

Я сменил ptr на std :: shared_ptr, и все это сработало.

Я полагаю, что могу использовать тот же код с общим указателем?

+0

Кстати, что такое 'OtherType'? Является ли он базовым классом с виртуальными функциями-членами? Вам нужен полиморфизм подтипа? – fredoverflow

+0

Это будет базовый класс с чистым виртуальным методом, как интерфейс. Мне просто нужно было бы назвать один из чистых виртуальных методов, не нужно бросать. Это что-то меняет? – Mark

+0

Интерфейсы являются ярким примером использования 'unique_ptr'. Больше никаких вопросов. – fredoverflow

ответ

0

otMap.find вернет rvalue, и, таким образом, это значение будет перемещено, если не RVO'd. Но, конечно, теперь ваша карта не имеет этого конкретного объекта. Кроме того, в прошлый раз, когда я проверил, find возвращает итератор, а не тип значения.

+0

YEah моя ошибка, но вы получаете jist. Надеюсь, – Mark

2

Что такое otMap?

Если otMap.find(name) возвращает std::unique_ptr<OtherType> как rvalue, тогда это будет нормально работать. Тем не менее, право собственности на указанное значение теперь переносится на возвращаемый указатель, поэтому значение больше не будет отображаться на карте. Это означало бы, что вы использовали пользовательский тип карты, а не std::map<>.

Если вы хотите, чтобы иметь возможность иметь значение в карте и возвращает указатель на него, то вам нужно использовать std::shared_ptr<OtherType> как в качестве типа значения карты и типа возвращаемого get_othertype().

std::map<std::string,std::shared_ptr<OtherType>> otMap; 
std::shared_ptr<OtherType> get_othertype(std::string name) 
{ 
    auto found=otMap.find(name); 
    if(found!=otMap.end()) 
     return found->second; 
    return std::shared_ptr<OtherType>(); 
} 
+0

. Я следил за советом из другого ответа отсюда http://stackoverflow.com/questions/3759119/creating-an-object-on-the-stack-then-passing- by-reference-to-another-method-in-c, где AshleysBrain предложил использовать unique_ptr для хранения в коллекции – Mark

+0

Накладные расходы 'shared_ptr' над' unique_ptr' небольшие (количество ссылок). Использование 'unique_ptr' в этом случае требует тщательного анализа, и я настоятельно рекомендую против него, если он действительно делает именно то, что вы хотите. –

+1

@Ant: Я не согласен. 'unique_ptr' четко выражает намерение программиста по карте *, владеющую * объектами, и делает код потенциально быстрее. Правильная реализация 'shared_ptr' должна учитывать безопасность потоков, чтобы получить правильное значение счетчика ссылок, что делает его потенциально намного медленнее, чем' unique_ptr'. – fredoverflow

11

Модель unique_ptr является передача права собственности. Если вы возвращаете unique_ptr объекту из функции, то никакие другие unique_ptr в системе не могут ссылаться на один и тот же объект.

Это то, что вы хотите? Я очень сомневаюсь в этом. Конечно, вы могли бы просто вернуть сырой указатель:

OtherType* get_othertype(const std::string& name) 
{ 
    return otMap.find(name)->second.get(); 
} 

Таким образом, клиент имеет доступ к объекту, но карта все еще владеет.

Вышеупомянутое решение довольно хрупкое, если запись не найдена под именем.Лучшим решением было бы либо выбросить исключение или возвращает нулевой указатель в этом случае:

#include <stdexcept> 

OtherType* get_othertype(const std::string& name) 
{ 
    auto it = otMap.find(name); 
    if (it == otMap.end()) throw std::invalid_argument("entry not found"); 
    return it->second.get(); 
} 

OtherType* get_othertype(const std::string& name) 
{ 
    auto it = otMap.find(name); 
    return (it == otMap.end()) ? 0 : it->second.get(); 
} 

И просто для полноты картины, вот предложение Энтони о возвращении ссылки:

OtherType& get_othertype(const std::string& name) 
{ 
    auto it = otMap.find(name); 
    if (it == otMap.end()) throw std::invalid_argument("entry not found"); 
    return *(it->second); 
} 

И вот как вернуть ссылку на unique_ptr внутри карты, но давайте сделаем, что ссылки на константные, так что клиент не случайно изменить оригинальный:

unique_ptr<OtherType> const& get_othertype(const std::string& name) 
{ 
    auto it = otMap.find(name); 
    if (it == otMap.end()) throw std::invalid_argument("entry not found"); 
    return it->second; 
} 
+1

Итак, каков стандартный способ сделать это? Я хотел бы, чтобы у вызывающего был указатель на объект, но карта все еще была владельцем. Однако я бы не хотел использовать сырье, поскольку вызывающий может не распоряжаться им? Что произойдет, если я удалю его из карты, его сыроедение ничего не укажет? – Mark

+1

@Mark: Гарантирован ли объект на карте? Если это так, то вы можете вернуть ссылку вместо указателя, и таким образом семантика вызова более явная: я дам вам доступ, но не права собственности. –

+0

Способ, которым система была разработана, если объект не был там, это было бы исключением. Референс-идея звучит как лучший вариант. – Mark

0

Вы бы решили изменить карту, чтобы удерживать shared_ptr s вместо unique_ptr s? Это сделает возвращение намного более безопасным. Весь смысл unique_ptr заключается в том, что он уникален (т. Е. не).

+2

Пункт уникальный * владение *. Это не исключает возможности других указателей на изображение, указывающих на один и тот же объект. В этом смысле он не сильно отличается от контейнера, который возвращает итератор. – sellibitze

Смежные вопросы