Commit 2f2db958 authored by Igor Kushnir's avatar Igor Kushnir
Browse files

Prevent copying and moving ScopedDialog
describes the issue solved by this commit. The blog post recommends
constraining the forwarding-reference constructor. But that solution
would require much more code than added in this commit. Especially
because the constraint would have to be expanded to support template
parameter pack.

The deleted constructor overloads prevent surprising and undesirable
compilation of the following two code snippets:
    ScopedDialog<QDialog> s;
    ScopedDialog<QDialog> s2(s);
    const ScopedDialog<QDialog> s;
    ScopedDialog<QDialog> s2(std::move(s));
They were compiled successfully because the forwarding-reference
constructor was a better match than the deleted copy and move
constructor respectively (due to const-qualifier differences). In the
forwarding-reference constructor invoked in these snippets, a reference
to ScopedDialog `s` was implicitly converted to QDialog* and passed as a
parent to `s2`'s new QDialog.

The final specifier prevents surprising and undesirable compilation of
the following code snippet (as well as the 3 other const and
rvalue-reference variations of it):
template <typename T> class ScopedDerived : public ScopedDialog<T> {};
void f() {
    ScopedDerived<QDialog> s;
    ScopedDialog<QDialog> s2(s);

A volatile ScopedDialog (which does not make sense, by the way) cannot
be copied or moved for another reason: passing volatile ScopedDialog as
`this` argument to `operator DialogType*() const` discards qualifiers.
parent 8902428e
Pipeline #104845 passed with stage
in 33 minutes and 30 seconds
......@@ -39,11 +39,20 @@ namespace KDevelop {
without need to manually clean up afterwards.
// This class template is final, because inheriting it shouldn't be useful, and
// the forwarding-reference constructor would be invoked in places where slicing
// normally occurs.
template<typename DialogType>
class ScopedDialog
class ScopedDialog final
// Explicitly delete unconventional overloads of copy and move constructors
// to prevent a compiler from using the forwarding-reference constructor in
// places where a copy or a move constructor are normally invoked.
ScopedDialog(ScopedDialog&) = delete;
ScopedDialog(const ScopedDialog&&) = delete;
/// Construct the dialog with any set of allowed arguments
/// for the construction of DialogType
template<typename ... Arguments>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment