-1
// B doesn't have a default constructor.
class A {
  public:
  A(Important resource) : b(resource) {}
  B b;
};

Reading about rule of three to figure out an issue with copying instances of a class into a vector.

So the issue is that we're generating instances inside a loop:

std::vector<A> some_vector(0);
for (int i = 0; i < 7; i++)
  some_vector.push_back(A(resources[i]));

From what we see with Valgrind, it smells like the copy constructor is mucking things up. When we change the code to:

std::vector<A*> some_vector(0);
for (int i = 0; i < 7; i++)
  some_vector.push_back(new A(resources[i]));

The the issue is alleviated. Don't like doing that though when it is not needed. So I'm thinking, how would the copy constructor know what to do when it is attempting to copy a class without a proper default constructor right?

Community
  • 1
  • 1
AturSams
  • 7,568
  • 18
  • 64
  • 98
  • 5
    "how would the copy constructor know what to do when it is attempting to copy a class without a proper default constructor right?" The two things are unrelated. Copying doesn't require default construction. – juanchopanza Aug 31 '15 at 06:29
  • 1
    Default constructors don't play a role in proper copying. You need a working copy constructor, and to write one you want your members and bases have working copy constructors. – n. m. could be an AI Aug 31 '15 at 06:31
  • 2
    It "smells like" `B` has a broken copy constructor. You should examine `B` to check that it behaves properly on copying/moving. – M.M Aug 31 '15 at 06:36
  • Wouldn't using a pointer of b instead of an actual b, solve this? – AturSams Aug 31 '15 at 06:48
  • 2
    @zehelvion No, fixing your bug would solve it. Using a pointer would hide your bug and change the semantics of the code. – juanchopanza Aug 31 '15 at 06:49

1 Answers1

3

For elements of a type T to be pushed into a std::vector in C++,

T must meet the requirements of CopyAssignable and CopyConstructible.

This means that it must have a working move or copy-constructor which will be used when creating new objects. It does not need a default constructor in general, but certain operations may require it, e.g. resize.

Being a resource in your example, it should probably be non-copyable, but maybe movable. If B does not have a correct copy-constructor, you will end up with a copy of the resource, and the destructor will release the resource more than once (e.g. deallocate memory or close a file).

For resources, the common pattern is to use RAII, e.g. std::unique_pointer for memory.

PS: Since C++11, there is a new type of constructor/assignment operator. The rule of three now becomes a rule of five, but it is best to not write copy- or assignment constructors at all when not dealing with resource-handling classes. Only these need to implement the operations, and other classes can just use it. This is rule of zero, and is what I would recommend to stick to. Again, std::unique_pointer is a good example. Instead of writing move/copy-constructors, your classes can just use a unique_ptr or shared_ptr, and memory management is taken care of.

Jens
  • 9,058
  • 2
  • 26
  • 43