38

Sorry, this might seem simple, but somebody asked me this, and I don't know for certain.

An empty C++ class comes with what functions?

Constructor, Copy Constructor, Assignment, Destructor?

Is that it? Or are there more?

Martin B
  • 23,670
  • 6
  • 53
  • 72

5 Answers5

55

In C++03 there are 4:

  • Default constructor: Declared only if no user-defined constructor is declared. Defined when used

  • Copy constructor - declared only if the user hasn't declared one. Defined if used

  • Copy-assignment operator same as above

  • Destructor same as above

In C++11 there are two more:

  • Move constructor
  • Move-assignment operator

It is also possible that the compiler won't be able to generate some of them. For example, if the class contains, for example, a reference (or anything else that cannot be copy-assigned), then the compiler won't be able to generate a copy-assignment operator for you. For more information read this

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 5
    It's actually up in the air as to whether the move constructor and move assignment operator will be implicitly declared in C++0x; there are papers by Dave Abrahams and Bjarne Stroustrup in the October WG21 mailing on this subject. There are concerns that having them implicitly declared may break legacy code. – James McNellis Oct 28 '10 at 15:44
  • 1
    I should think having a reference as a member variable would prevent generation of the default assignment operator, not cause problems with the copy constructor. – Ben Voigt Oct 28 '10 at 18:10
  • @James: That sounds very interesting. Could you perhaps provide a link to discussion of this topic? – Armen Tsirunyan Oct 28 '10 at 18:13
  • 1
    They are both listed in [the October 2010 mailing on the WG21 website](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/#mailing2010-10). See Bjarne Stroustrup's "To Move or Not To Move" (N3174) and Dave Abraham's "Implicit Move Must Go" (N3153). I haven't had time to read either of them yet; Anthony Williams has a brief summary of the issues to be discussed at Batavia [on his blog](http://www.justsoftwaresolutions.co.uk/cplusplus/cplusplus-standards-committee-mailing-october-2010.html). – James McNellis Oct 28 '10 at 18:29
  • Are new and delete there? are they considered operators of the class? –  Oct 28 '10 at 18:33
  • @PhilCK: You see, there are global new and delete, and your class uses them unless you overload new and delete in your class. The same is with address-of operator. So now, new and deleted and & are not declared specially for your class – Armen Tsirunyan Oct 28 '10 at 18:35
  • 1
    I haven't had time to read Stroustrup's paper yet, but the one by Abrahams made a pretty convincing case for no implicit move functions. Still, it'll be interesting to see how it turns out. It would be nice if they could get implicit move working without breaking existing code, but it seems like there's no obvious way to do it. – jalf Oct 28 '10 at 18:45
  • I also read Abrahams' paper and felt he was right, and that was a bad news for me. Later I read Stroustrup's paper and got very impressed by his vision, and the solutions he brings where there seemed to be no solution. – rafak Oct 28 '10 at 22:17
14

If I define the following class

class X
{};

The compiler will define the following methods:

X::X()  {}                    // Default constructor. It takes zero arguments (hence default).
X::~X() {}                    // Destructor
X::X(X const& rhs) {};        // Copy constructor
X& operator=(X const& rhs)
{return *this;}              // Assignment operator.

// Since C++11 we also define move operations
X::X(X&& rhs) {};            // Move Constructor
X& operator=(X&& rhs)
{return *this;}              // Move Assignment

Note:
The default constructor is not built if ANY constructor is defined.
The other methods are not built if the user defines an alternative.

What is slightly more interesting is the default implementation when we have members and a base:

class Y: public X
{
    int    a;      // POD data
    int*   b;      // POD (that also happens to be a pointer)
    Z      z;      // A class
};

// Note: There are two variants of the default constructor.
//       Both are used depending on context when the compiler defined version
//       of the default constructor is used.
//
//       One does `default initialization`
//       One does `zero initialization`

// Objects are zero initialized when
//   They are 'static storage duration'
//   **OR** You use the braces when using the default constructor
Y::Y()      // Zero initializer
    : X()   // Zero initializer
    , a(0)
    , b(0)
    , z()   // Zero initializer of Z called.
{}

// Objects are default initialized when
//    They are 'automatic storage duration'
//    **AND** don't use the braces when using the default constructor
Y::Y()
    :X    // Not legal syntax trying to portray default initialization of X (base class)
    //,a  // POD: uninitialized.
    //,b  // POD: uninitialized.
    ,z    // Not legal syntax trying to portray default initialization of z (member)
{}
//
// Note: It is actually hard to correctly zero initialize a 'automatic storage duration'
//       variable (because of the parsing problems it tends to end up a a function
//       declaration). Thus in a function context member variables can have indeterminate
//       values because of default initialization. Thus it is always good practice to 
//       to initialize all members of your class during construction (preferably in the
//       initialization list).
//
// Note: This was defined this way so that the C++ is backward compatible with C.
//       And obeys the rule of don't do more than you need too (because we want the C++
//       code to be as fast and efficient as possible.


Y::Y(Y const& rhs)
    :X(rhs)              // Copy construct the base
    ,a(rhs.a)            // Copy construct each member using the copy constructor.
    ,b(rhs.b)            // NOTE: The order is explicitly defined
    ,z(rhs.z)            //       as the order of declaration in the class.
{}

Y& operator=(Y const& rhs)
{
    X::operator=(rhs);   // Use base copy assignment operator
    a  = rhs.a;          // Use the copy assignment operator on each member.
    b  = rhs.b;          // NOTE: The order is explicitly defined
    z  = rhs.z;          //       as the order of declaration in the class.
    return(*this);
}

Y::~Y()
{
    Your Code first
}
// Not legal code. Trying to show what happens.
  : ~z()
  , ~b() // Does nothing for pointers.
  , ~a() // Does nothing for POD types
  , ~X() ; // Base class destructed last.


// Move semantics:
Y::Y(Y&& rhs)
    :X(std::move(rhs))   // Move construct the base
    ,a(std::move(rhs.a)) // Move construct each member using the copy constructor.
    ,b(std::move(rhs.b)) // NOTE: The order is explicitly defined
    ,z(std::move(rhs.z)) //       as the order of declaration in the class.
{}

Y& operator=(Y&& rhs)
{
    X::operator=(std::move(rhs));   // Use base move assignment operator
    a  = std::move(rhs.a);          // Use the move assignment operator on each member.
    b  = std::move(rhs.b);          // NOTE: The order is explicitly defined
    z  = std::move(rhs.z);          //       as the order of declaration in the class.
    return(*this);
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    Your assignment operator definition if flawed because you don't have a return statement inside a non-void function. – Prasoon Saurav Oct 28 '10 at 15:28
  • And assignment operator returns constant reference, value or void. – Šimon Tóth Oct 28 '10 at 15:30
  • @Let_Me_Be: No. It returns a reference. Try using an object after assignment. – Martin York Oct 28 '10 at 15:43
  • @Martin If you are talking `(a=b).something()` then yes, by returning a reference you can do that, but it is definitely a very bad practice. Plus note, that by returning a constant reference you can still invoke constant methods. – Šimon Tóth Oct 28 '10 at 15:45
  • @Let: No, it is a very good practice. Wherever possible, the semantics of overloaded operators should match the semantics of the built-in operators. _Using_ the reference returned by an assignment may be a bad idea, but that doesn't mean an assignment operator shouldn't return the reference in the first place. – James McNellis Oct 28 '10 at 15:50
  • @James Oh and I suppose that you think that this will actually work? `int x = 10, y = 20; (x = y) = 10;` – Šimon Tóth Oct 28 '10 at 15:54
  • @Let_Me_Be: it is good practice to do so. As it follows the semantics of the language and **it is how the default implementation works**. The following should work fine: X a;X b; (a = b).doSomthing(); – Martin York Oct 28 '10 at 15:57
  • @Martin As I already presented it definitely doesn't follow the semantics of the language. – Šimon Tóth Oct 28 '10 at 15:59
  • @Let_Me_Be: It depends on your definition of "work." Will it compile? Yes (the answer to the next question notwithstanding). Is the behavior defined? No. What are you getting at? – James McNellis Oct 28 '10 at 16:03
  • @James No it won't compile. If it does then you should start using a different compiler, because the one you are using is broken. – Šimon Tóth Oct 28 '10 at 16:05
  • @Let_Me_Be: Why would it not compile? The result of an assignment is an lvalue. [For what it's worth, Comeau, g++, and Visual C++ all compile it successfully, which is to be expected.] – James McNellis Oct 28 '10 at 16:11
  • Good coding follows the principle of least surprise. Most developers expect the assignment operator to return a reference to the object (because the default assignemnt operator does). So that is what you should do. – Martin York Oct 28 '10 at 16:12
  • You are right, standard actually defines the result of assignment to be lvalue. Sorry I got confused by C, where the result is rvalue. – Šimon Tóth Oct 28 '10 at 16:27
  • @James C++03: The result of the assignment operation is the value stored in the left operand after the assignment has taken place; the result is an lvalue. C99: An assignment expression has the value of the left operand after the assignment, but is not an lvalue. – Šimon Tóth Oct 28 '10 at 16:32
  • The default constructor is not built(implicitly declared) if ANY constructor is *defined*. **declared** would be more correct – Armen Tsirunyan Oct 28 '10 at 18:16
  • @Armen: Nope, sorry. I read your sentence backwards. (I switched defined and declared.) – GManNickG Oct 28 '10 at 19:17
11

Just to expand on Armen Tsirunyan answer here are the signatures for the methods:

// C++03
MyClass();                                     // Default constructor
MyClass(const MyClass& other);                 // Copy constructor
MyClass& operator=(const MyClass& other);      // Copy assignment operator
~MyClass();                                    // Destructor

// C++11 adds two more
MyClass(MyClass&& other) noexcept;             // Move constructor
MyClass& operator=(MyClass&& other) noexcept;  // Move assignment operator
Community
  • 1
  • 1
Victor Stepanov
  • 111
  • 1
  • 2
0

Default methods assigned by compiler for a empty class:

http://cplusplusinterviews.blogspot.sg/2015/04/compiler-default-methods.html

rvkreddy
  • 183
  • 1
  • 9
  • 2
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. Please take a look here: [Why and how are some answers deleted?](http://stackoverflow.com/help/deleted-answers) – bummi Apr 23 '15 at 05:18
-1

Is that it?

Yes thats it.

Compiler generates by default

  • A default constructor
  • A copy constructor
  • A copy assignment operator
  • A destructor

for a class

You can see the default constructor, the copy constructor and the assignment operator being generated by default when you use -ast-dump option of Clang

prasoon@prasoon-desktop ~ $ cat empty.cpp && clang++ -cc1 -ast-dump empty.cpp
class empty
{};

int main()
{
   empty e;
   empty e2 = e;
   {
     empty e3;
     e3 = e;
   }

}
typedef char *__builtin_va_list;
class empty {
    class empty;
    inline empty() throw(); //default c-tor
    //copy c-tor
    inline empty(empty const &) throw() (CompoundStmt 0xa0b1050 <empty.cpp:1:7>)

    //assignment operator   
    inline empty &operator=(empty const &) throw() (CompoundStmt 0xa0b1590 <empty.cpp:1:7>
  (ReturnStmt 0xa0b1578 <col:7>
    (UnaryOperator 0xa0b1558 <col:7> 'class empty' prefix '*'
      (CXXThisExpr 0xa0b1538 <col:7> 'class empty *' this))))


};
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • i don't think that destructor is really generated. – Andrey Oct 28 '10 at 15:23
  • 4
    It is, the default destructor just calls the destructors on all the members. If it didn't do this all the members would leak whenever the parent object was destructed. – AshleysBrain Oct 28 '10 at 15:26
  • 2
    @Ashley Actually not, the destructor doesn't call anything. This is done outside the destructor. – Šimon Tóth Oct 28 '10 at 15:31
  • 2
    The default destructor does call something - the destructors of all members. It's just done implicitly at the end of the destructor so you don't have to write it all out yourself. That's still a bunch of calls being made, which is effectively a subroutine. It's also *still part of the destructor* whether you write your own or not. I don't see how it's "outside" the destructor, because the user destructor and automatic destruction of members *always* go together. – AshleysBrain Oct 28 '10 at 15:47
  • 1
    @Ashley Nope, that is done outside the destructor. Same for constructors (that's why the initialization list exists), once you enter the body of the constructor all constructors of members and ancestors were already called. – Šimon Tóth Oct 28 '10 at 15:57
  • 5
    @Let_Me_Be: It is correct to say that it is the destructor that does this. "After executing the body of the destructor and destroying any automatic objects allocated within the body, __a destructor for class `X` calls the destructors__ for `X`’s direct members, the destructors for X’s direct base classes and, if `X` is the type of the most derived class (12.6.2), its destructor calls the destructors for `X`’s virtual base classes." (C++03 12.4/6) – James McNellis Oct 28 '10 at 16:08