Я пытаюсь оборачивать голову тем, как должны работать семантика перемещения на С++ 11, и у меня возникают проблемы с пониманием того, какие условия должен удовлетворять перемещаемый объект. Глядя на ответ здесь, на самом деле не разрешает мой вопрос, потому что не может понять, как применить его к объектам pimpl разумным образом, несмотря на аргументы, что перемещение семантики идеально подходит для pimpls.
Самая простая иллюстрация моей проблемы связана с идиомой pimpl, например:
class Foo {
std::unique_ptr<FooImpl> impl_;
public:
// Inlining FooImpl constructors for brevity sake; otherwise it
// defeats the point.
Foo() : impl_(new FooImpl()) {}
Foo(const Foo & rhs) : impl_(new FooImpl(*rhs.impl_)) {}
Foo(Foo && rhs) : impl_(std::move(rhs.impl_)) {}
Foo & operator=(Foo rhs)
{
std::swap(impl_, rhs.impl_);
return *this;
}
void do_stuff ()
{
impl_->do_stuff;
}
};
Теперь, что я могу сделать, как только перейду с Foo
? Я могу безопасно уничтожить перемещенный объект, и я могу назначить ему, оба из которых абсолютно необходимы. Однако, если я попытаюсь do_stuff
с моим Foo
, он взорвется. Прежде чем я добавил семантику перемещения для моего определения Foo
, каждый Foo
удовлетворял инварианту, что он мог бы do_stuff
, и это уже не так. Похоже, что не существует большого количества альтернатив, так как (например), когда переносимый из Foo
будет включать новое динамическое распределение, которое частично побеждает цель семантики перемещения. Я мог бы проверить, есть ли impl_
в do_stuff
и инициализировать его по умолчанию FooImpl
, если он есть, но добавляет (обычно ложную) проверку, и если у меня много методов, это означало бы запоминание делать проверку в каждом.
Должен ли я просто отказаться от идеи, что возможность do_stuff
является разумным инвариантом?