C ++: инициализировать (новый) массив векторов разного начального размера - PullRequest
0 голосов
/ 30 апреля 2018

Чтобы помочь вам в этом, я даю свои коды: (main.cpp), задействован только один файл.

#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;
}

Я намерен инициализировать vp[0] размером 10 и vp[1] размером 20. Однако, когда я скомпилировал его на mac, используя g++ -std=c++11 main.cpp -o main, он пожаловался:

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);
         ^

В CentOS Linux, используя ту же команду, и я получил

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>]’

Что здесь происходит? Почему это связано с ключевым словом explicit? Я знаю, что вектор имеет несколько конструкторов (например, тот, что с аргументом типа initializer-list). Если я инициализирую вектор как vector<test> temp {10}, это будет инициализировать вектор размером 10 без каких-либо проблем explicit. Я не знаю, что скрыто внутри, когда дело доходит до vector<test> array[2] {{10},{20}}, что вызывает у меня ошибку.

Интересно, что если я предоставлю классу test конструктор с одним аргументом (просто раскомментируем строку в моем коде), компилятор вообще не будет жаловаться. Но значение vector<test> array[2] {{10},{20}} изменилось, чтобы инициализировать вектор array[0] объектами типа 2 test, инициализированными с 10 и 20 соответственно. Но синтаксис vector<test> array[2] {10,20}, который я попробовал позже, снова неверен.

Я не знаю, что здесь происходит, и я полностью потерян. Разве {10,20} не относится к типу списка инициализаторов?

Я очень ценю, если вы можете объяснить, что здесь происходит, и как инициализировать массив векторов разного размера (пожалуйста, не используйте обходные пути). Я хочу знать, что именно означает синтаксис.

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Вы инициализируете vector<test> объекты с кодом: vector<test> array[2] {{10},{20}}. Ошибка, которую вы получаете от использования vector::vector(size_t count) конструктора , который равен explicit. Этот vector конструктор будет создавать count по умолчанию построенные test объекты.
Так, например, если бы это не было определено как explicit, вы бы получили array[0], содержащий 10 построенных по умолчанию test объектов, и array[1], содержащий 20 построенных по умолчанию test объектов. Если бы вы намеревались сделать это, вы бы явно сконструировали объекты vector:

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

Вы действительно хотели создать тестовые объекты в vector с, так что этот eplicit фактически защищает вас от случайного завершения непреднамеренного выделения vector с.

Когда вы добавляете в конструктор test:test(int param), {{10},{20}} по-прежнему не может использовать конструктор explicit vector. Но теперь это можно рассматривать как инициализация списка из vector[0]. Но так же, как если бы вы сделали: int array[2] = {42} и элемент 2 nd будет инициализирован нулем; так и ваши 2 и vector в этом случае не будут инициализированы.

0 голосов
/ 30 апреля 2018

Во-первых, конструктор explicit допускается при прямой инициализации, но не при инициализации копирования.

Затем в совокупная инициализация ,

(акцент мой)

Каждый direct public base, (since C++17) элемент массива или нестатический член класса в порядке индекса / появления массива в определении класса инициализируется копией из соответствующего предложения списка инициализатора.

Это означает, что new vector<test>[2] {{10},{20}};, {10} и {20} используются для копирования-инициализации vector<test> элементов; тогда конструкторы explicit не рассматриваются.

И

Если я инициализирую вектор как vector<test> temp {10}, это будет инициализировать вектор размером 10 без каких-либо проблем explicit.

Поскольку конструктор explicit разрешен в прямой инициализации ,

Прямая инициализация более разрешительна, чем инициализация копирования: при инициализации копирования учитываются только неявные конструкторы и неявные пользовательские функции преобразования, тогда как при прямой инициализации учитываются все конструкторы и все пользовательские функции преобразования.

По той же причине new vector<test>[2] {std::vector<test>{10},std::vector<test>{20}}; тоже работает.

КСТАТИ:

если я предоставлю классу test конструктор с одним аргументом (просто раскомментируем строку в моем коде), компилятор вообще не будет жаловаться.

Если вы предоставите конструктор, который может быть использован для неявного преобразования int в test, тогда {10} может быть использован для построения std::initializer_list<test>, тогда конструктор std::vector<test>, который принимает std::initializer_list<test> вызывается, потому что это всегда предпочтительнее. Кстати, если вы сделаете конструктор из test explicit, код тоже не будет работать.

...