Внешний шаблонный класс vector<unique_ptr <... >> альтернатива

Это началось с вопроса: "Почему невозможно явно создать экземпляр std::vector из std::unique_ptr?" как в:

template class std::vector<std::unique_ptr<int>>;

хотя следующие явные экземпляры и переменные хороши:

template class std::vector<int>;
template class std::unique_ptr<int>;

int main() {
    std::vector<int> ints;
    std::vector<std::unique_ptr<int>> pointers;
}

Но вопрос изменился на: "Какими будут альтернативы?"

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

1 ответ

Почему это невозможно?

Это невозможно сделать:

template class std::vector<std::unique_ptr<int>>; // (1)

Хотя компилятор вполне подходит для такой переменной:

std::vector<std::unique_ptr<int>> vec; // (2)

Насколько я понимаю, (2) возможно, потому что методы, использующие назначения / конструкторы копирования, никогда неявно не создаются в векторе;
и (1) невозможно, потому что вектор пытается создать экземпляры методов, пытающихся сделать копии на unique_ptr.

Первый способ не скомпилировать для gcc 7.2.1 C++17, например, vector::push_back(const T&);

Поскольку T = unique_ptr, а unique_ptr, очевидно, не поддерживает операции копирования.

Какие есть альтернативы?

shared_ptr вместо unique_ptr работает, потому что поддерживает копирование, а также выглядит чисто. Но, как я слышал, у него есть некоторые накладные расходы, и мы не намерены делиться правами собственности на ресурсы.

Я также представляю, как написать оболочку, которая определяет операции "копирования", которые фактически будут перемещаться при копировании или даже выбросе, например:

template<typename T>
struct UniquePtrWithCopy {
    /*mutable if move is used*/ std::unique_ptr<T> mPtr;

    UniquePtrWithCopy() = default;

    explicit UniquePtrWithCopy(std::unique_ptr<T>&& other)
            : mPtr{std::move(other)} {
    }

    UniquePtrWithCopy(const UniquePtrWithCopy& other) {
        mPtr = std::move(other.mPtr); // needed for operations, like resize
        // or
        throw std::runtime_error{"This is not intended"};
    }

    UniquePtrWithCopy& operator =(const UniquePtrWithCopy& other) {
        if(this != &other) {
            mPtr = std::move(other.mPtr);
        }
        return *this;
        // or
        throw std::runtime_error{"This is not intended"};
    }
};

И тогда это возможно:

template class std::vector<UniquePtrWithMovingCopy<int>>;

Так что, думаю, хотя я и пытался найти ответ, я все-таки нашел его сам, но я был бы рад услышать некоторые другие способы или исправления.

Было бы неплохо, однако, если бы компилятор выполнил какой-то трюк sfinae и только частично создал экземпляр того, что возможно, но это, вероятно, имеет свои собственные проблемы.

Другие вопросы по тегам