Извлечение члена std::unique_ptr с помощью std::move() из класса, который недействителен при значении null: как избежатьC++

Программы на C++. Форум разработчиков
Anonymous
 Извлечение члена std::unique_ptr с помощью std::move() из класса, который недействителен при значении null: как избежать

Сообщение Anonymous »

Рассмотрим следующий сценарий.
У нас есть класс bar, который владеет объектом данных foo через уникальный указатель. Панель всегда должна быть переведена в допустимое состояние; то есть bar всегда должен владеть некоторыми данными, поэтому данные никогда не должны быть нулевыми. Мы можем вызвать get_data(), чтобы просмотреть данные bar, но право собственности на эти данные не должно меняться, пока bar жив. Итак, данные добавляются в bar, когда мы его создаем: конструктор принимает уникальный указатель через семантику перемещения.
Затем у нас есть baz, который может владеть несколько данных foo. Мы можем добавлять данные по одному, используя add_data(), используя std::move() для перемещения данных в baz. Пока все хорошо.

Код: Выделить всё

struct foo {};

class bar
{
public:
bar(std::unique_ptr data) : data{ std::move(data) }
{
if (!this->data)
{
throw std::invalid_argument{ "Unexpected null pointer" };
}
}

foo* get_data() { return (this->data).get(); }
private:
std::unique_ptr data;
};

class baz
{
public:
baz() = default;

void add_data(std::unique_ptr data) { vec.push_back(std::move(data)); }
private:
std::vector vec;
};

int main()
{
// bar invalid_bar{ std::unique_ptr() }; // throws an exception

std::unique_ptr data_0{ std::make_unique() };
bar bar_0{ std::move(data_0) };

std::unique_ptr data_1{ std::make_unique() };
std::unique_ptr data_2{ std::make_unique() };
std::unique_ptr data_3{ std::make_unique() };
baz baz_0;
baz_0.add_data(std::move(data_1));
baz_0.add_data(std::move(data_2));
baz_0.add_data(std::move(data_3));
}
Теперь я хочу иметь возможность объединять данные в bar с данными в baz:

Код: Выделить всё

void merge_data(baz& target, bar&& source)
{
// ...
}
В отличие от приведенного примера кода, эти классы вместо этого могут представлять большие структуры данных, и в этом случае лучше избегать ненужного копирования. Целью этой функции является получение панели с помощью семантики перемещения, и все данные, хранящиеся на ней, теперь передаются в baz.
Проблема в том, что , для этого необходимо извлечь данные из bar вместе с указанием владельца. Это означает, что полоса останется в недопустимом нулевом состоянии. Это извлечение допустимо, если оно происходит внутри merge_data(), поскольку полоса перемещается, поэтому полученная недействительная полоса не должна увидеть свет. Однако извлечение этих данных потребует добавления функции-члена, доступной для merge_data(). Итак, я рассматриваю возможность добавления в bar следующего открытого члена:

Код: Выделить всё

std::unique_ptr extract_data() { return std::move(this->data); }
Это нормально, но есть одна проблема: поскольку это общедоступный файл, это означает, что существует риск того, что он может быть вызван в середине жизни foo
code>, рискуя получить foo в недопустимом нулевом состоянии в середине использования. Возможно, я знаю, что вызов этой функции оставит недействительную полосу, и имейте в виду, что после этого просто не используйте полосу. Но я подозреваю, что это будет неприятным сюрпризом для других пользователей, которые увидят эту функцию и думают, что извлеченные данные только копируются из bar!
Как я могу разрешить это extract_data (), не оставляя ничего не подозревающих недействительных объектов bar?

Подробнее здесь: https://stackoverflow.com/questions/790 ... at-is-inva

Вернуться в «C++»