Странная ошибка при попытке сделать swap shared_ptr ()
Я относительный новичок в C++, пытающийся преобразовать существующий проект из необработанных указателей с запутанным протоколом управления памятью в использование C++11 shared_ptr
, В целом все идет очень гладко, и я думаю, что понимаю, как shared_ptr
работает с точки зрения семантики перемещения, ссылок на значения и т. д. Хорошие вещи.
Однако я натолкнулся на странную ошибку, которую не понимаю и не могу исправить. Сначала немного истории. У меня есть иерархия классов коренится в абстрактном базовом классе с именем EidosValue
и класс с именем EidosValue_Int_vector
является (косвенно) конкретным подклассом этого:
class EidosValue
class EidosValue_Int : public EidosValue
class EidosValue_Int_vector : public EidosValue_Int
Мой код вообще трафик в EidosValue
, но иногда, особенно при создании нового значения, мне нужно обрабатывать определенный подкласс.
Я сделал typedefs для shared_ptr
s для этих классов, поэтому у меня есть:
typedef std::shared_ptr<EidosValue> EidosValue_SP;
typedef std::shared_ptr<EidosValue_Int_vector> EidosValue_Int_vector_SP;
среди других. Хорошо, теперь к сути проблемы. У меня есть функция, которая возвращает EidosValue_SP
что это создает. В зависимости от логики внутри функции, она может создать один из нескольких конкретных подклассов EidosValue
, Поэтому я делаю что-то вроде этого:
EidosValue_SP MyClass::MyMethod(...)
{
EidosValue_SP result;
if (...)
{
EidosValue_Int_vector_SP int_result_SP = make_shared<EidosValue_Int_vector>();
... do subclass-specific stuff with int_result_SP...
result.swap(int_result_SP);
}
else (...)
{
...similar logic for other subclasses...
}
...other shared logic...
return result;
}
Проблема с swap()
вызов. Я получаю ошибку: " Non-const lvalue reference to type 'shared_ptr<EidosValue>' cannot bind to a value of unrelated type 'shared_ptr<EidosValue_Int_vector>'
". Это загадочно, так как EidosValue_Int_vector
это не "не связанный тип", это открытый подкласс EidosValue, и код здесь это знает. Если я наберу result = make_shared<EidosValue_Int_vector>();
у компилятора нет никаких проблем с этим, поэтому он четко знает, что типы связаны и совместимы. Это просто не нравится в контексте swap()
по какой-то причине. В других местах в моем проекте я мог просто сделать return int_result_SP;
с объявленным типом возврата EidosValue_SP, и это сработало нормально - компилятор с радостью рассматривает EidosValue_Int_vector_SP как EidosValue_SP в этом контексте - но я не могу сделать это здесь из-за общей логики в нижней части функции,
Я несколько ограничен в своей реализации здесь, потому что этот код является узким местом и должен быстро выполняться (и да, я знаю это по факту инструментирования кода, и да, это действительно имеет значение). Поэтому важно использовать make_shared
чтобы избежать двойного распределения, и я также настоятельно предпочел бы избегать увеличения / уменьшения счетчика при передаче указателя из int_result_SP
в результате; Я не хочу, чтобы был момент времени, когда есть два shared_ptrs, указывающих на новый экземпляр. Так swap()
кажется очевидным путем; но я заблокирован этой ошибкой компилятора. Почему это происходит и как я могу это исправить? Спасибо!
ДОПОЛНЕНИЕ:
О, размышляя об этом, держу пари, я знаю, почему происходит ошибка. swap()
не возражает против EidosValue_Int_vector
в EidosValue_SP
, но у него есть проблема с EidosValue
в EidosValue_Int_vector_SP
; в этом направлении типы не совместимы. Я не думал об этом с тех пор result
не имеет значения (т.е. имеет nullptr
Наверное) в этом; но конечно swap()
не знает этого Хорошо, так что если это проблема, то остается вопрос: как я могу осуществить передачу, сохраняя при этом код быстро - не делая refcount inc/dec и не отказываясь от использования make_shared
? Теперь, когда я понимаю проблему (я думаю), кажется вероятным, что есть какой-то API или трюк, который я упустил из виду...
2 ответа
Это именно то, что std::move
для. Использование:
result = std::move (int_result_SP);
Ты не можешь swap
потому что, хотя EidosValue_Int_vector
это EidosValue
обратное неверно.