Remix.run Logo
▲ quietbritishjim 3 hours ago

I followed the link near the start to the article about std::indirect<T>, which you can use instead of std::unique_ptr<T> for the pImpl idiom: [1]

> Never null: it always holds a value, except in the moved-from state (but features a member function called valueless_after_move() that lets you check the state)

Ugh, what a mess. Surely the whole point of using this rather than unique_ptr is to avoid such a trap! A safe move constructor isn't possible here because you'd either have to re-init your moved-from object, or do element-wise move (with `MyClass(MyClass&& other): impl(std::in_place, *other.impl) {}`) but those would stop your move constructor being noexcept. It would've been much more useful to make the move constructor of indirect be deleted, which is what people typically did with a pImpl-based classes in the past.

[1] https://mariusbancila.ro/blog/2026/07/23/the-pimpl-idiom-and...

▲dgrunwald 2 hours ago | parent [-]

> It would've been much more useful to make the move constructor of indirect be deleted

No, that would be less useful. As-is, you can use a class with a `std::indirect<T>` member in a `std::vector` just fine, thanks to the move constructor.

With `std::indirect` in `std::vector`, the vector can use move the `indirect` internally when reallocating, and as a user of the vector you will never encounter the moved-from state.

It's annoying that C++ doesn't have destructive move and thus needs to relax class invariants after a move happened, but in practice it's usually not a big deal because use-after-move is usually a bug, nothing anyone would do intentionally.

▲OskarS an hour ago | parent [-]

I agree. The comment is correct in that it sort-of violates the "purity" of std::indirect that it has this pathological in moved-from state, but it's only an issue when directly using moved-from objects, which is something you essentially never do. Exactly what you say, "in practice" this never happens. Throwing the move constructor out because of it would be throwing out the baby with the bathwater.

std::variant has a similar issue with valueless_after_exception, which given the semantics of the language, it has to have. But similarly, this essentially never happens in practice, and I've never encountered a bug with a valueless std::variant.