11

To fill a std::vector<struct_name> from std::cin, I usually write as following code:

struct point{
    int x, y;
};

int main()
{
   std::size_t n;
   std::cin>>n; 
   std::vector<point> vec(n);
    for (auto& p:vec) 
        std::cin>>p.x>>p.y;
   //...
}

But today I found out another way to do it with default constructor:

struct point{
int x, y;
   point(){
      std::cin>>x>>y;
   }
};

int main()
{
    std::size_t n;
    std::cin>>n; 
    std::vector<point> vec(n);
    //...
}

Questions:

  1. Is the initialization order of the vector elements guaranteed by the standard(0,1,2,n-1...)?
  2. (If answer of previous question is true) Is really the second variant has twice effective?

I am interested in behavior according to the C++11(and newer) standard

cigien
  • 57,834
  • 11
  • 73
  • 112
PavelDev
  • 579
  • 4
  • 12
  • 4
    Quite apart from the problem of whether the order is guaranteed, using the constructor to input data like this looks horrible to me. A constructor should be as 'clean' as possible. Your first solution looks better. – TonyK Dec 14 '20 at 15:41
  • std::cin is maybe really no good example I think.But the question wether I can overload a function there is really interesting. – benni Jan 11 '21 at 09:41

2 Answers2

13

It is not guaranteed that the elements are initialized in the order of their indices. In C++11, see [vector.cons]/3:

Effects: Constructs a vector with n value-initialized elements.

This says nothing about the ordering, so nothing can be assumed. The wording changes in later editions of the standard, but no ordering ever seems to have been imposed.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
6

On your first question, the C++20 (but this goes back to C++11 as well) section dealing with the vector sequence container makes no promises about the order in which elements are constructed within the vector itself, only that the elements are set to some specific value:

Effects: Constructs a vector with n default-inserted elements.

Nothing at all about the order in that (very brief) section(a).

But you have a bigger problem with your method, specifically I don't think you really want to go out to cin for every case where you're default constructing a point variable.

There may be, for example, cases where you need a default-constructed temporary variable and it's going to be seen as a hang if your program suddenly stops to accept user input, especially without some prompt to the user :-)


That makes your second question moot but, assuming you're concerned about inefficiencies in initialising vector elements then changing them with an input loop, I wouldn't be. The structure with no constructor (i.e., just a couple of int variables) doesn't need to initialise them(b), so a vector of them can just do the allocation and stop there.


(a) Some order is guaranteed in the standard, such as the order of disparate members within a class, or the order of elements within an array. However, the elements of a vector are neither of those things.


(b) This is covered in C++20 10.9 Iniitialisation [class.init]:

When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form (), the object is initialized as specified in 9.3.

and C++20 9.3 Initializers [dcl.init]:

To default-initialize an object of type T means:

  • If T is a (possibly cv-qualified) class type, constructors are considered. The applicable constructors are enumerated, and the best one for the initializer () is chosen through overload resolution. The constructor thus selected is called, with an empty argument list, to initialize the object.
  • If T is an array type, each element is default-initialized.
  • Otherwise, no initialization is performed.

It's that first bullet point that kicks in for a type with no constructors explicitly defined or inherited. In that case, it uses the implicitly-defined constructor which is equivalent to a user defined constructor with no body and no initialiser list.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • @paxdiablo Thanks! But I am aware of this problem. I just practice in solving a small teaching task. And I assumed that the second option would increase efficiency. But if order is not guaranteed then I should to stay on the first option. – PavelDev Dec 14 '20 at 01:58
  • @PavelDev: see my updates on your potential efficiency gains. Even if order *was* guaranteed, I don't think you'd see much improvement, since the creation of a vector of default-initialised members would basically just be the memory allocation - there would be no double-setting of elements in the vector. – paxdiablo Dec 14 '20 at 02:22
  • 1
    @paxdiablo -- even if the default constructor of `point` initializes both members to some value, the time taken to do that would be swamped by the time taken later to read in the actual values. I/O is slow; anything that's done internally is instantaneous compared to that. – Pete Becker Dec 14 '20 at 13:59