What's the point in defaulting functions in C++11?
Asked Answered
D

8

22

C++11 adds the ability for telling the compiler to create a default implementation of any of the special member functions. While I can see the value of deleting a function, where's the value of explicitly defaulting a function? Just leave it blank and the compiler will do it anyway.

The only point I can see is that a default constructor is only created when no other constructor exists:

class eg {
public:
    eg(int i);
    eg() = default; 
};

But is that really better than how you do it now?

class eg {
public:
    eg(int i);
    eg() {}
};

Or am I missing a use-case?

Desmond answered 5/5, 2009 at 8:49 Comment(0)
S
20

A defaulted constructor will have a declaration, and that declaration will be subject to the normal access rules. E.g. you can make the default copy constructor protected. Without these new declarations, the default generated members are public.

Skull answered 5/5, 2009 at 9:4 Comment(1)
[dig] Additionally: defining certain special member functions prevents the compiler from defaulting others, but this can be re-enabled with = default. For example, if you implement a custom copy constructor then the default move constructor will not be generated. Rather than implementing it yourself, you can explicitly default it if that would be sufficient.Orebro
N
17

Those examples from Stroustrup's website might help you understand the point:

defaulted and deleted functions -- control of defaults

The common idiom of "prohibiting copying" can now be expressed directly:

class X {
  // ...

  X& operator=(const X&) = delete;    // Disallow copying
  X(const X&) = delete;
};

Conversely, we can also say explicitly that we want to default copy behavior:

class Y {
  // ...
  Y& operator=(const Y&) = default;   // default copy semantics
  Y(const Y&) = default;

};

Being explicit about the default is obviously redundant, but comments to that effect and (worse) a user explicitly defining copy operations meant to give the default behavior are not uncommon. Leaving it to the compiler to implement the default behavior is simpler, less error-prone, and often leads to better object code. The "default" mechanism can be used for any function that has a default. The "delete" mechanism can be used for any function. For example, we can eliminate an undesired conversion like this:

struct Z {
  // ...

  Z(long long);     // can initialize with an long long
  Z(long) = delete; // but not anything less
};
Neanderthal answered 5/5, 2009 at 9:34 Comment(2)
I actually asked the question after reading BS's C++0x FAQ, his "obviously redundant" comment prompted me to question the whole defaulting issue.Desmond
Hm,, bummer you can use =delete on anything but not =default. Would have loved to write "int main() = default; // Go back to reading StackOverflow"Skull
A
13

As well as changing the accessibility (private/protected) of generated functions, you will be able to make them virtual.

struct S
{
    virtual ~S();
    virtual S& operator=(const S&);
};

S::~S() = default;
S& S::operator=(const S&) = default;

The following aspects of defaulted functions can be modified:

  • access (be made non-public)
  • virtual
  • explicit (constructors)
  • exception specifications
  • const-ness of parameters

but to do so, the functions must be defined outside the class (8.4.2/2 in the C++0x Final Committee Draft).

A version of the original proposal by Lawrence Crowl is here.

Thanks to Roger Pate for the clarification and citation.

Award answered 5/5, 2009 at 10:4 Comment(6)
Why does gcc 4.5.0 emit the following error for the code you posted: 'virtual S::~S()' declared virtual cannot be defaulted in the class bodyInterpose
@bpw: Because 8.4.2/2 (checked in N3092) explicitly forbids this code.Rightful
@Roger Thanks for the clarification (elsewhere). As you pointed out is required, I've defined the functions outside the class.Award
Is there some ambiguity that is caused by defining it in the class body? It seems odd that you can say virtual ~Class() {} in the body of Class, but not virtual ~Class() = default; Is there any difference in behavior between those two pieces of code in any situation?Roundel
@David Only that it would implicitly be inline, I supposeAward
This restriction is no longer imposed on newer drafts (N3376 for me and sequential C++14 drafts). So you can declare virtual ~Class() = default.Danaus
F
2

1) Implicitly generated destructors are currently not virtual. So you need to define them in order to make them virtual, in which case they are not as efficient. With =default, You will have both virtual and efficent as implicitly generated destructors.

2) They will have access specifiers, contrary to implicitly generated ones.

3) If you inline your defaulted constructor, your class still remain trivial.

Here is an article elaborating this new feature.

Frowsy answered 5/5, 2009 at 10:31 Comment(0)
S
1

I suspect that being able to default generate the copy constructor will be actually useful. I can't see a use for default generating the default constructor since as you say the implementation you type in would be shorter.

Superfuse answered 5/5, 2009 at 8:55 Comment(0)
U
1

See Item 17 from Scott Meyer's great book "Effective Modern C++". It describes many conditions under which default copy constructors, copy operations, and move operations are generated (or NOT generated).

In other words, the compiler might not "do it anyway". But if the default special member function makes sense, the user could use the "default" keyword to explicitly tell the compiler to generate a default function that otherwise not be generated.

From the Things to Remember at the end of Item 17:

  • Move operations are generated only for classes lacking explicitly declared move operations, copy operations, or a destructor.

  • The copy constructor is generated only for classes lacking an explicitly declared copy constructor, and it’s deleted if a move operation is declared. The copy assignment operator is generated only for classes lacking an explicitly declared copy assignment operator, and it’s deleted if a move operation is declared. Generation of the copy operations in classes with an explicitly declared destructor is deprecated.

Untouchability answered 3/11, 2016 at 16:35 Comment(0)
S
0

For me its the disabling feature that will be useful, For most of the classes I currently create I disable copying & assignment - it will be nice to have a feature the compiler can recognise to do this, rather than depending on linker errors.

Sharpie answered 5/5, 2009 at 9:1 Comment(2)
Even now (C++98) by deriving from a non_copyable class you can have the compiler detect the errors (even when used in the class itself) and don't have to wait for link time.Desmond
I don't believe in introducing derivation to solve problems like this.Sharpie
L
0

Defaulting is more useful for copy-constructors if you have a class with lots of attributes. For example, if you have this class:

class MyClass {
private:
   int offset;
   std::string name;
   std::vector<Person*> relatives;
   float weight;
   MyClass* spouse;
   Vehicle* car;
   double houseArea;
   Date birth;
   Person* parents[2];

public:
   /* Default constructor will be defined here */
};

instead of defining the copy-constructor this way:

MyClass(const MyClass& that) :
   offset(that.offset),
   name(that.name),
   relatives(that.relatives),
   weight(that.weight),
   spouse(that.spouse),
   car(that.car),
   houseArea(that.houseArea),
   birth(that.birth),
   parents(that.parents)
{}

you would define this way:

MyClass(const MyClass&) = default;
Lues answered 7/9, 2011 at 1:46 Comment(1)
Yeahbut default copy constructors are created by the compiler automaticallyDesmond

© 2022 - 2024 — McMap. All rights reserved.