C++ : initialize(new) an array of vector of different initial size

99封情书 提交于 2019-12-11 09:09:11

问题


To help you get the point, I give my codes:(main.cpp),only one file involved.

#include <iostream>
#include <vector>
using namespace std;
class test{
public : 
    int member {0};
    void fun(){cout << "member is " << member << endl;}
    test(){}
    //test(int param) : member(param){} //this line is commented.
};

int main()
{
    vector<test> *vp = new vector<test>[2] {{10},{20}};
    //vector<test> array[2] {{10},{20}};//this won't work either.
    cout << "size of vp[0] is " << vp[0].size() << endl;
    cout << "size of vp[1] is " << vp[1].size() << endl;
    return 0;
}

I intend to initialize vp[0] to size 10 and vp[1] to size 20. However when I compiled it on mac using g++ -std=c++11 main.cpp -o main it complained:

main.cpp:14:45: error: chosen constructor is explicit in copy-initialization
    vector<test> *vp = new vector<test>[2] {{10},{20}};
                                            ^~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:517:14: note: 
      constructor declared here
    explicit vector(size_type __n);
             ^
main.cpp:14:50: error: chosen constructor is explicit in copy-initialization
    vector<test> *vp = new vector<test>[2] {{10},{20}};
                                                 ^~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:517:14: note: 
      constructor declared here
    explicit vector(size_type __n);
         ^

In CentOS Linux using the same command and I got

main.cpp: In function ‘int main()’:
main.cpp:14:54: error: converting to ‘std::vector<test>’ from initializer list would use explicit constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = test; _Alloc = std::allocator<test>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<test>]’
     vector<test> *vp = new vector<test>[2] {{10},{20}};
                                                      ^
main.cpp:14:54: error: converting to ‘std::vector<test>’ from initializer list would use explicit constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = test; _Alloc = std::allocator<test>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<test>]’

What is going on here? Why does it have anything to do with keyword explicit? I know vector have several constructors(such as the one with initializer-list type argument). If I initialize the vector like vector<test> temp {10}, this would initialize vector to be of size 10 without any explicit concerns. I don't know what is hidden inside when it comes to vector<test> array[2] {{10},{20}} that cause me the bug.

Interestingly, if I provide class test with a constructor with one argument(just uncomment the line in my code), the compiler does not complain at all. But the meaning of vector<test> array[2] {{10},{20}} changed to initialize the vector array[0] with 2 test type objects initialized with 10 and 20 respectively. But the syntax vector<test> array[2] {10,20},which i tried later, is wrong again.

I don't know what is going on here and am totally lost. Isn't {10,20} of initializer-list type too?

I really appreciate it if you can explain what's going on here, and how to initialize an array of vector of different size(please do not use circumventing ways). I want to know what does the syntax means exactly.


回答1:


Firstly, explicit constructor is allowed in direct-initialization, but not copy-initialization.

Then, in aggregate initialization,

(emphasis mine)

Each direct public base, (since C++17) array element, or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from the corresponding clause of the initializer list.

That means for new vector<test>[2] {{10},{20}};, {10} and {20} are used to copy-initialize the vector<test> elements; then the explicit constructors are not considered.

And

If I initialize the vector like vector<test> temp {10}, this would initialize vector to be of size 10 without any explicit concerns.

Because explicit constructor is allowed in direct initialization,

Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and non-explicit user-defined conversion functions, while direct-initialization considers all constructors and all user-defined conversion functions.

For the same reason new vector<test>[2] {std::vector<test>{10},std::vector<test>{20}}; works too.

BTW:

if I provide class test with a constructor with one argument(just uncomment the line in my code), the compiler does not complain at all.

If you provide a constructor which could be used to convert int to test implicitly, then {10} could be used to construct an std::initializer_list<test>, then the constructor of std::vector<test> which taking std::initializer_list<test> is invoked because it's always preferred. BTW If you make the constructor of test explicit the code would fail too.




回答2:


You are initializing vector<test> objects with the code: vector<test> array[2] {{10},{20}}. The error you're getting is from using the vector::vector(size_t count) constructor which is explicit. This vector constructor would construct count default constructed test objects.
So for example if this hadn't been defined as explicit you would have ended up with array[0] containing 10 default constructed test objects, and array[1] containing 20 default constructed test object. If you had intended to do this you would have to have constructed the vector objects explicitly:

vector<test> foo[] = { vector<test>{ 10 }, vector<test>{ 20 } }

You really wanted to construct test objects into the vectors so this eplicit is in fact protecting you from accidentally ending up allocating unintended vectors.

When you add in the test:test(int param) constructor {{10},{20}} still fails to use the explicit vector constructor. But this can now be treated as list initialization of vector[0]. But similarly to if you'd done: int array[2] = {42} and the 2nd element would be zero-initialized; so too your 2ndvector will be uninitialized in this case.



来源:https://stackoverflow.com/questions/50100705/c-initializenew-an-array-of-vector-of-different-initial-size

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!