Перенос владения умным указателем в контейнер - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть структуры данных, которые обычно управляются через std::unique_ptr, например, выражения в AST.

struct BinExpr {
 std::unique_ptr<Expr> left;    // Left owns the expression
 std::unique_ptr<Expr> right;   // Right owns the expression
};

, который хорошо работает в большинстве ситуаций.

Но иногда я делаюне иметь фиксированного количества выражений для владения, например, в списке

struct ListExpr {
  std::vector<std::unique_ptr<Expr>> exprs; // Exprs owns pointers which each own an expression 
};

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

Но у меня проблема в том, что выражения всегда создаются в умных указателях (или, по крайней мере, в виде необработанных указателей):

std::unique_ptr<Expr> parse_expr() { ... }

Существует ли элегантный способ передачи владения от вызовов parse_expr (которые имеют тип std::unique_ptr<Expr> к std::vector<Expr>? Конечно, при этом Expr нельзя копировать при этом.как

std::vector<Expr> exprs;
exprs.push_back(move_from_ptr_to_vec(parse_expr()));

В общем, в настоящее время я использую их вот так

std::vector<std::unique_ptr<Expr>> exprs;
exprs.push_back(std::move(parse_expr()));
return std::unique_ptr<ListExpr>(exprs);   // List has a std::vector<std::unique_ptr<Expr>>

но я так хочу

std::vector<Expr> exprs;
exprs.push_back(parse_expr());
return std::unique_ptr<ListExpr>(exprs);   // List has a std::vector<Expr>

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019
std::vector<Expr> exprs;
exprs.push_back(parse_expr());

Не работает, потому что parse_expr() возвращает умный указатель.Вы должны сделать косвенный указатель через указатель, чтобы получить указанный объект:

exprs.push_back(*parse_expr());

Expr не должны копироваться при этом.

Затем двигаться, предполагая, что этоОК:

exprs.push_back(std::move(*parse_expr()));

Тем не менее, рассмотрим , почему их выражения в первую очередь динамически размещаются.Предположительно, они являются указателями на полиморфные базовые подобъекты.В таком случае перемещение с базы, вероятно, не будет полезным для вас, и вся концепция массива базовых объектов, вероятно, неверна.

Expr может быть базовым классом

В этом случае std::vector<std::unique_ptr<Expr>> - это то, что вам нужно.

0 голосов
/ 26 февраля 2019

Предполагая, что ваш Expr является полиморфным или даже абстрактным базовым классом, вкратце: нет.std::vector для конкретных типов, и если вы храните простые указатели в нем, вы немедленно подчиняетесь правилу n, n> 3. Вам нужно будет вручную delete Expr s, что в настоящее время std::unique_ptr делаетдля тебя.И создание более автоматизированного контейнера абстрактного типа вряд ли стоит усилий.

Кстати, std::unique_ptr ничего не владеет.Одна из его основных целей состоит в том, чтобы позволить классам владеть своими членами, которые по какой-то причине не могут быть немедленно сохранены по стоимости;Быть абстрактной базой - вполне законный пример такой причины.Помните: вы владеете своими объектами, а не указателем;все, что он делает, это освобождает вас от ненужного бремени базового управления вашими объектами.

...