c++constructor

Why does clang think I have a copy constructor?


I have a struct with these special member functions:

struct MyStruct {
    MyStruct(MyStruct& other) = delete;

    MyStruct(MyStruct&& other) = default;

    explicit MyStruct(int num) noexcept(false);

    explicit MyStruct(MyOtherStructType&& other_type);

    ~MyStruct();

    auto operator=(MyStruct&& other) noexcept(false) -> MyStruct&;
}

clang tidy says:

Class 'MyStruct' defines a non-default destructor, a copy constructor, a move
constructor and a move assignment operator but does not define a copy assignment
operator

Due to the hicpp-special-member-functions/cppcoreguidelines-special-member-functions lint, however I thought I deleted the copy constructor? Did I miss anything? Is the lint wrong?


Solution

  • The rule-of-five applies to all other special member functions once you explicitly declare any special member function, not only when you provide a custom definition for one. Defining a function as deleted still counts for this.

    Note that defining a function as deleted is not the same as not declaring the function at all (whether implicitly or explicitly). A function defined as deleted still is declared and participates in overload resolution as normal. The only meaning it has is that if overload resolution would chose the deleted function, then the overload resolution will be considered ill-formed.

    The reason that the rule should also apply when the copy constructor is deleted is because deleting the copy constructor does not prevent the implicit definition of the copy assignment operator.

    But if you explicitly deleted the copy constructor, then it is quite likely that your type shouldn't have the default copy semantics on assignment either. The rule-of-five makes sure that you don't forget about declaring the correct semantics for the copy assignment operator, which if you want the compiler defaults can be declared by defining the overload as = default.

    As it stands, writing

    MyStruct x(1);
    MyStruct y = x;
    

    is ill-formed, but

    MyStruct x(1);
    MyStruct y(2);
    y = x;
    

    will compile with the compiler-generated default copy behavior, which is likely wrong for your type if you deleted the copy constructor.


    Also, a copy constructor or copy assignment operator should take its parameter as const reference. Not following this convention will cause you problems. Because the deleted overload still participates in overload resolution, it still matters whether or not it uses const.