9

Here is my code. If I remove default constructor, there will be error below. But if I add a default constructor, it will have no issues compiling and running. Wondering why? I am especially confused since default constructor is not used at all in runtime, why it is required at compile time?

#include <iostream>
#include <vector>
#include <string>

class Foo {
 public:
  //Foo();
  Foo(const std::string& name, double score);
  Foo(const Foo& other);
  Foo(Foo&& other);
  const std::string& name() const { return name_; }
  double score() const { return score_; }

 private:
  std::string name_;
  double score_;
};

/*
Foo::Foo() {
  std::cout << "In default constructor " << std::endl;
  name_ = "foo";
  score_ = 1.0;
}*/

Foo::Foo(const std::string& name, double score) : name_(name), score_(score) {
  std::cout << "In parametered constructor " << std::endl;
}

Foo::Foo(const Foo& other) {
  std::cout << "In copy constructor " << std::endl;
  name_ = other.name();
  score_ = other.score();
}

Foo::Foo(Foo&& other)
    : name_(std::move(other.name())), score_(std::move(other.score())) {
  std::cout << "In move constructor " << std::endl;
}

int main(int argc, char** argv) {
  std::vector<Foo> students;
  students.emplace_back("name1", 4.0);
  students.emplace_back("name2", 5.0);
  std::cout << "resizing begin " << std::endl;
  students.resize(1);
  for (Foo student : students) {
    std::cout << "student name: " << student.name()
              << " student score: " << student.score() << std::endl;
  }
  return 0;
}

Error message when there is no default constructor,

Error:
  required from 'static _ForwardIterator std::__uninitialized_default_n_1<_TrivialValueType>::__uninit_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Foo*; _Size = long unsigned int; bool _TrivialValueType = false]'

Successful run output when there is default constructor,

In parametered constructor 
In parametered constructor 
In copy constructor 
resizing begin 
In copy constructor 
student name: name1 student score: 4
Lin Ma
  • 9,739
  • 32
  • 105
  • 175
  • 1
    And you don't need all those other constructors. –  Apr 29 '18 at 00:17
  • 8
    Calling `resize` for some arguments might require a default constructor to grow the vector. It doesn't do static analysis to determine if you only ever shrink the vector – M.M Apr 29 '18 at 00:17
  • @NeilButterworth, thx, and could you answer directly to my specific question? :) – Lin Ma May 01 '18 at 04:11
  • Thanks @M.M, what do you mean "some arguments"? Do you mean for some specific use case of `resize` or for all use cases of `resize`, we all need default constructor? – Lin Ma May 01 '18 at 04:12
  • 2
    @LinMa to grow the vector via `resize` elements must be default-constructed – M.M May 01 '18 at 04:14

2 Answers2

5

The issue is your call to resize (specifically, students.resize(1)); when that line is removed, the code compiles. The issue is that resize has to initialize the new elements if it wasn't large enough, thus it needs the default constructor. If you want to shrink the size of your students without ensuring it's a sufficient size, you can use erase (Max Vollmer has a specific example).

Information on resize is available at cppreference. You're falling into the first (single argument) form.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
  • [`reserve`](http://en.cppreference.com/w/cpp/container/vector/reserve) doesn't work here. From the docs: If `new_cap` is greater than the current `capacity()`, new storage is allocated, **otherwise the method does nothing.** [...] `reserve()` **cannot be used to reduce the capacity of the container** [...]. – Max Vollmer May 01 '18 at 08:31
  • @MaxVollmer - That's what I get for looking up `resize` but going off memory for `reserve`. Thanks for keeping me honest :). – Stephen Newell May 01 '18 at 08:52
3

Instead of students.resize(1);, which needs a default constructor, you can do students.pop_back();, or, if the size of your vector can vary, students.erase(students.begin()+1, students.end());.

Max Vollmer
  • 8,412
  • 9
  • 28
  • 43