Инициализация массива объектов без оператора =, конструктора копирования или конструктора по умолчанию и аргументов времени выполнения

отказ

Я пытаюсь выделить массив объектов, которые не являются ни копируемыми, ни назначаемыми, ни имеют конструктор по умолчанию. У объектов есть аргументы, которые определяются во время выполнения. Я знаю, что вы можете решить эту проблему, имея массив указателей или умно используя новые размещения, но меня больше интересует, возможно ли это сделать чисто с помощью магии C ++ 11 (1y). Поэтому, пожалуйста, это чисто теоретический интерес, поэтому избегайте попыток решить «мою проблему», предлагая обходные пути.

Код…

…Итак, вопрос: есть ли способ заставить следующую работу работать в C ++ 11 или C ++ 14:

class X{
public:
explicit X(int a){...}
X(const X&) = delete;
void operator = (const X&) = delete;
private:
...
};

class Y{
public:
Y(const std::vector<int>& args) {
x = new X[]{args};
}
~Y(){
delete [] x;
}
private:
X* x;
};

критерии

В частности, я ищу решение / конструкцию, которая соответствует следующим критериям:

  • X не копируется конструктивно.
  • Х не присваивается.
  • X не имеет конструктора по умолчанию без аргументов (конструкция имеет побочные эффекты).
  • Аргументы конструктора X не известны до времени выполнения.
  • Все случаи X должны быть расположены в памяти непрерывно.
  • X должен быть должным образом разрушен, когда массив удален из его базового указателя (или если промежуточный класс используется, когда промежуточный объект разрушен). Это исключает множество указателей и наивно использует размещение новых.

Редактировать / Дополнение

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

3

Решение

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

Это означает, что вам нужно вместо этого выделить необработанную память и использовать размещение new для создания объектов. Вы можете обернуть это в векторный класс с фиксированным пространством.

template <typename T>
class fixed_capacity_vector {
public:
using size_type = std::size_t;

fixed_capacity_vector(size_type capacity)
: data_(::operator new(capacity * sizeof(T)), size_(), capacity_(capacity)
{}

fixed_capacity_vector(const fixed_capacity_vector&) = delete;
fixed_capacity_vector(fixed_capacity_vector&&) = delete;
fixed_capacity_vector& operator =(const fixed_capacity_vector&) = delete;
fixed_capacity_vector& operator =(fixed_capacity_vector&&) = delete;

~fixed_capacity_vector() {
for (size_type i = 0; i < size_; ++i) data_[i].~T();
::operator delete(data_);
}

template <typename... Args>
T& emplace_back(Args&&... args) {
if (size_ == capacity_) throw out_of_range();
new (data_ + size_) T(std::forward<Args>(args)...);
++size_;
return data_[size_-1];
}

private:
T* data_;
size_type size_;
size_type capacity_;
};
3

Другие решения

Ты можешь использовать std::vector И его emplace_back функционировать, если вы делаете X по крайней мере подвижный.

class X{
public:
explicit X(int){}
X(X&&) = default;
X(const X&) = delete;
void operator = (const X&) = delete;
};

int main() {
std::vector<X> xs;
xs.emplace_back(0);
xs.emplace_back(1);
xs.emplace_back(2);
xs.emplace_back(3);
}

(Если вы объявляете конструктор копирования, даже если это объявление удаляет его, компилятор не будет автоматически генерировать какие-либо специальные элементы перемещения, поэтому вам необходимо явно запросить их)

Это в основном сводится к стратегии «массив с размещением нового», но все абстрагируется в понятия высокого уровня.

Если вы не можете использовать подвижный тип, вы должны реализовать вектороподобный класс, который предварительно выделяет память и никогда не перераспределяет. Ничего подобного в стандартной библиотеке нет.

4

Вам придется следить за созданными элементами вручную, но вы можете использовать allocator помогать:

class Y{
public:
Y(const std::vector<int>& args):
alloc{},
n{args.size()},
x{alloc.allocate(n)}
{
auto end = x;
try {
for (auto arg: args)
alloc.construct(end++, arg);
} catch (...) {
while (end != x)
alloc.destroy(--end);
alloc.deallocate(x, n);
throw;
}
}
~Y() {
for (auto end = std::next(x, n); end != x; --end)
alloc.destroy(end);
alloc.deallocate(x, n);
}
private:
std::allocator<X> alloc;
const std::size_t n;
const X *x;
};
4
По вопросам рекламы [email protected]