Увеличение размера динамического массива, реализуемого на shared_ptr

Есть метод push_back для динамического массива.

void TVector::push_back(const Square& value) {
    if(_size == 0){
        auto _array = std::make_shared<std::array<Square, 1>>();
        (*_array)[0] = value;
        _size++;
    }
    else{
        auto _array = std::make_shared<std::array<Square, _size>>();
        (*_array)[_size] = value;
        _size++;
    }
}

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

auto _array = std::make_shared<std::array<Square, _size>>();

жалуется IDE таким образом Non-type template argument is not a constant expression. Подскажите, есть ли какой-то способ похожий на realloc по смыслу для умного указателя shared_ptr, чтобы можно было реализовать данный метод.


Ответы (1 шт):

Автор решения: Никита Самоуков

Всё сложно, тут одна из основных проблем темплейтов в C++.

Дело в том, что при компиле

std::array<Square, 1>
std::array<Square, 2>
std::array<Square, 3>

Компилятор генерит разный код для каждого из 3 типов. Для C++ это 3 совершенно различных типа. И такое не скомпилится:

std::shared_ptr<std::array<int, 4242>> p=std::make_shared<std::array<int, 42>>();

Но раз уж пошли таким путём, то если очень постараться, то можно запилить такое.

Для начала понадобится массив типов. https://stackoverflow.com/questions/24015710/for-loop-over-template-arguments-types

Массив соответственно из:

std::array<Square, 1>
std::array<Square, 2>
std::array<Square, 4>
std::array<Square, 8>

Можно и не кратные 2 если хочется.

Далее так как это всё разные типы, то нельзя просто так:

std::shared_ptr<std::array<int, 4242>> p=std::make_shared<std::array<int, 42>>();

Нам нужен либо variant, либо void

std::shared_ptr<std::variant<all_types array 1 2 4 8>>
std::shared_ptr<void>

Далее что-то типо такого:

std::variant<all_types array 1 2 4 8> make_shared_of(int size){
    std::optional<std::variant<all_types array 1 2 4 8>> res;
    for_<all_types array 1 2 4 8>([&]<typename T>(T* type_dummy){
        if(!res && T().size() >= size)
            res = T();
    });
    return *res;
}

void TVector::resize(int size) {
    auto _array = make_shared_of(size);
    _size = size;
    // copy array data...
}

void TVector::push_back(const Square& value) {
    resize(_size + 1);
    std::visit([&](auto&& arg){arg[_size - 1] = value;}, array);
}

О том какого размер будет .exe, и как быстро компилиться, и работать я не буду упоминать.

→ Ссылка