Copy constructors/destructors

I've been reading about how to write your own copy constructors and destructors when using classes. I tried writing a simple program just to get a feel for the concepts. I created a class called "Song," and then in main(), I created a vector called allSongs which contains Song objects. Song objects are instantiated using data entered by the user (like song title, composer, etc.).

In my copy constructor and destructor, I put in this line
 
cout << "Copy constructor/destructor called\n";

so I would know when they were called. I was expecting to only see this message when a Song object was duplicated or deleted, but to my surprise, the message also appeared any time a new Song object was instantiated. I'm instantiating new Song objects with this line:
 
allSongs.push_back(Song(usrTitle, usrComp, usrKey, usrBpm));

I also noticed that those messages appear multiple times, depending on how many Song objects are in the vector. So, for example, when I push_back a third Song object to the vector, I see this:

Copy constructor called

Copy constructor called

Copy constructor called

Destructor called

Destructor called

Destructor called

So, I'm just wondering why they are being called when I'm not explicitly duplicating or deleting objects. Does it have something to do with the fact that I'm using a vector, instead of individual variables?

Thanks.
closed account (Dy7SLyTq)
a) there is no such thing as a copy contstructor.
b) you can't have a copy constructor/destructor; their two different things. you cant explicitly delete objects. its going to get called whenever an object goes out of scope. as to it calling the copy constructor can you post your code?
When we insert an object into a standard container, the container makes its own copy of the object.

In addition, when a std::vector<> allocates a new buffer (typically when the current buffer is not large enough), it copies (or if possible, moves) the objects it holds into the new buffer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <string>
#include <iostream>
#include <vector>

struct Song
{
    Song( const std::string& name, const std::string& by )
        : title(name), artiste(by) { std::cout << "Song::two arg constructor\n" ; }

    Song( const Song& that ) : title(that.title), artiste(that.artiste)
    { std::cout << "Song::copy constructor\n" ; }

    const std::string title ;
    const std::string artiste ;
};

int main()
{
    std::vector<Song> favourites ; // empty sequence
    favourites.reserve(5) ; // reserve space for upto 5 songs

    Song autumn( "Autumn in New York", "Billie Holiday" ) ; // Song::two arg constructor
    favourites.push_back(autumn) ; // vector makes a copy: Song::copy constructor


    std::cout << '\n' ;
    // 1. construct an anonymous song object and pass that to push_back()
    // 2. the vector makes a copy
    favourites.push_back( Song( "Summertime", "Sarah Vaughan" ) ) ;
    // Song::two arg constructor
    // Song::copy constructor


    std::cout << '\n' ;
    // construct a song object in situ inside the vector (avoids the extra copy)
    favourites.emplace_back( "It Might as Well Be Spring", "Astrud Gilberto" ) ;
    // Song::two arg constructor


    std::cout << '\n' ;
    // allocate memory for a new buffer which can hold upto 50 songs
    // copy the three songs into the new buffer
    favourites.reserve(50) ; // reserve space for upto 50 songs
    // Song::copy constructor
    // Song::copy constructor
    // Song::copy constructor
}

http://ideone.com/RgfJ3c
closed account (Dy7SLyTq)
i fail to see any country in that post jlb. so much respect lost
Thank you JLBorges, that was very helpful. I see now why the copy constructor is called whenever I use push_back in my allSongs vector. I'm still not totally clear on why the destructor is also called when I add to the vector. I was expecting to see the destructor used when an object goes out of scope, or when I use
 
allSongs.erase((allSongs.begin())+x);

to delete a particular Song object within the vector. But not when I add to the vector.

And DSTCode, yes, of course I understand that the copy constructor and the destructor are not the same thing. I didn't mean to imply that they were. And I don't know why you would say that there's no such thing as a copy constructor.
> I'm still not totally clear on why the destructor is also called when I add to the vector.

1
2
3
4
5
6
7
8
9
10
// 1. construct an anonymous song object (constructor) and pass that to push_back()
// 2. the vector makes a copy of the song object (copy constructor)
// 3. life-time of the anonymous object created in step 1 is over; it is destroyed (destructor)
favourites.push_back( Song( "Summertime", "Sarah Vaughan" ) ) ;

// 1. allocate memory for a new buffer which can hold upto 50 songs
// 2 a. copy the three songs into the new buffer (copy constructor x 3 )
// 2 b. destroy the song objects in the old buffer (destructor x 3 )
// 3. release memory that the old buffer occupies
favourites.reserve(50) ; // reserve space for upto 50 songs 
closed account (Dy7SLyTq)
ok i was just making sure. and i meant that you meant you had a copy constructor/destructor lumped together. i didnt mean that you cant have a copy constructor
Okay, now I get it. I like to know what's going on under the hood. Thanks for giving me such a detailed explanation, JLB.
Now make Song moveable (nothrow_move_constructible) and we find that the vector moves (rather than copies) Song objects where possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <string>
#include <iostream>
#include <vector>
#include <type_traits>

struct Song
{
    Song( const std::string& name, const std::string& by )
        : title(name), artiste(by) { std::cout << "    Song::two arg constructor\n" ; }

    Song( const Song& that ) : title(that.title), artiste(that.artiste)
    { std::cout << "    Song::copy constructor\n" ; }

    Song( Song&& that ) noexcept
        : title( std::move(that.title) ), artiste( std::move(that.artiste) )
    { std::cout << "    Song::move constructor\n" ; }

    ~Song() noexcept { std::cout << "    Song::destructor\n" ; } ;

    Song& operator= ( const Song& that ) = default ;
    Song& operator= ( Song&& that ) noexcept = default ;

    const std::string title ;
    const std::string artiste ;
};

int main()
{
    std::cout << "is_nothrow_move_constructible? " << std::boolalpha
               << std::is_nothrow_move_constructible<Song>::value << '\n' // true
               << "is_nothrow_destructible? " << std::boolalpha
               << std::is_nothrow_destructible<Song>::value << "\n\n" ; // true

    std::vector<Song> favourites ; // empty sequence
    favourites.reserve(5) ; // reserve space for upto 5 songs

    std::cout << "Song autumn(...) ;\n" ;
    Song autumn( "Autumn in New York", "Billie Holiday" ) ; // Song::two arg constructor

    std::cout << "\nfavourites.push_back(autumn) ;\n" ;
    {
        favourites.push_back(autumn) ; // vector makes a copy: Song::copy constructor
    }

    std::cout << "\nfavourites.push_back( Song(...) ) ;\n" ;
    {
        favourites.push_back( Song( "Summertime", "Sarah Vaughan" ) ) ;
    }


    std::cout << "\nfavourites.emplace_back(...) ;\n" ;
    {
        favourites.emplace_back( "It Might as Well Be Spring", "Astrud Gilberto" ) ;
    }

    std::cout << "\nfavourites.reserve(50) ;\n" ;
    {
        favourites.reserve(50) ; // reserve space for upto 50 songs
    }

    std::cout << "\nend of main: local object autumn and the vector destroyed\n" ;
}





























is_nothrow_move_constructible? true
is_nothrow_destructible? true





Song autumn(...) ;
    Song::two arg constructor


favourites.push_back(autumn) ;
    Song::copy constructor


favourites.push_back( Song(...) ) ;
    Song::two arg constructor
    Song::move constructor
    Song::destructor



favourites.emplace_back(...) ;
    Song::two arg constructor

favourites.reserve(50) ;
    Song::move constructor
    Song::move constructor
    Song::move constructor
    Song::destructor
    Song::destructor
    Song::destructor 

end of main: autumn, vector destroyed
    Song::destructor
    Song::destructor
    Song::destructor
    Song::destructor

http://coliru.stacked-crooked.com/a/adc0c6fdfe393117
Topic archived. No new replies allowed.