Создать экземпляр объекта из приведенного std::shared_ptr

#c #c 11

#c #c 11

Вопрос:

У меня есть вектор, который содержит набор общих указателей:

 std::vector<std::shared_ptr<Derived>> originalVector;
  

В какой-то момент он был приведен к Base общим указателям, это выглядит как:

 std::vector<std::shared_ptr<Base>>* castedVector = reinterpret_cast<std::vector<std::shared_ptr<Base>>*>(amp;originalVector);
  

Как добавить Derived элемент в приведенный вектор? По-видимому, я могу поместить в него пустой std::shared_ptr , знает ли этот новый общий указатель что-либо о типе, который он содержит, может ли он создать объект этого типа?

Обновление: Невозможно создать исходный объект после shared_ptr приведения к базовому классу. После приведения он теряет всю информацию об исходном базовом типе. Более того: это reinterpret_cast неопределенное поведение.

Комментарии:

1. В C нет «неявных приведений». Существуют неявные преобразования. Приведение — это выражение, которое программист явно записывает для запроса преобразования. И преобразование в вашем примере никогда не произойдет неявно. Приведение наверняка было.

2. @StoryTeller Да, вы правы, я только что привел этот вектор к базе, взломал, но работает. Вопрос все еще присутствует, по-видимому, {std::shared_ptr} не имеет никакой фабрики, но что, если это так)))

3. «взломать, но работает» — очень опасный взлом. coliru.stacked-crooked.com/a/20a276a9b5a1a7ae — Неопределенное поведение не определено.

4. @user1810087 просто static_cast я добавляю это к вопросу

5. Единственная причина, по которой я упомянул UB, заключается в том, что это похоже на вопрос XY . Я полагаю, что вы пропустили шаг в описании вашей проблемы.

Ответ №1:

Вы должны иметь возможность добавлять указатель производного класса к вектору указателей базового класса. Затем производный указатель преобразуется в базовый указатель. Это вроде как не зависит от того, что делают интеллектуальные указатели. Не имеет значения, был ли вектор создан как вектор базовых элементов или он был преобразован в такой, не так ли?

 std::vector<std::shared_ptr<Base>> bases;

// Create a Derived instance
auto derived = std::make_shared<Derived>();
bases.push_back(derived);

// Only create a pointer (might as well just create a Base pointer)
std::shared_ptr<Derived> emptyPointer;
bases.push_back(emptyPointer)
  

Комментарии:

1. Это было бы слишком просто, у меня нет type в этот момент (только Base), поэтому я не могу вызвать std::make_shared.

2. Первоначально вектор был создан как std::vector<std::shared_ptr<Derived>> затем приведен к std::vector<std::shared_ptr<Base>>*

3. Если вы не можете создать экземпляр объекта, вы также можете просто создать объект shared_ptr<Производный> и добавить его в вектор (отредактированный ответ). Но вы должны быть очень осторожны, потому что доступ к этому указателю, конечно, приводит к ошибкам доступа… Я все еще не совсем уверен в том, чего вы пытаетесь достичь 🙂

4. Опять же, для вызова shared_ptr<Derived> мне нужен тип, я могу создать только пустой std::shared_ptr , мне нужно как-то создать объект для него, не зная типа.

5. Если вы не знаете тип, как вы узнаете, что он наследуется от Base?

Ответ №2:

 std::vector<std::shared_ptr<Base>>* castedVector =
    reinterpret_cast<std::vector<std::shared_ptr<Base>>*>(amp;originalVector);
  

Это неопределенное поведение, не делайте этого.

Вы можете создать vector набор указателей на базу путем копирования, а не путем лжи системе типов:

 std::vector<std::shared_ptr<Base>> baseVector(originalVector.begin(), originalVector.end());
  

Это содержит копии исходных указателей, которые разделяют с ними права собственности, но содержащиеся указатели являются Base* верхними Derived* .

Очевидно, что если вы вставите новое значение в originalVector , оно не будет в baseVector , поэтому вам нужно будет создать новую копию всего originalVector или вставить его в оба одновременно.