У нас есть класс 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));
}
Код: Выделить всё
void merge_data(baz& target, bar&& source)
{
// ...
}
Проблема в том, что , для этого необходимо извлечь данные из bar вместе с указанием владельца. Это означает, что полоса останется в недопустимом нулевом состоянии. Это извлечение допустимо, если оно происходит внутри merge_data(), поскольку полоса перемещается, поэтому полученная недействительная полоса не должна увидеть свет. Однако извлечение этих данных потребует добавления функции-члена, доступной для merge_data(). Итак, я рассматриваю возможность добавления в bar следующего открытого члена:
Код: Выделить всё
std::unique_ptr extract_data() { return std::move(this->data); }
code>, рискуя получить foo в недопустимом нулевом состоянии в середине использования. Возможно, я знаю, что вызов этой функции оставит недействительную полосу, и имейте в виду, что после этого просто не используйте полосу. Но я подозреваю, что это будет неприятным сюрпризом для других пользователей, которые увидят эту функцию и думают, что извлеченные данные только копируются из bar!
Как я могу разрешить это extract_data (), не оставляя ничего не подозревающих недействительных объектов bar?
Подробнее здесь: https://stackoverflow.com/questions/790 ... at-is-inva