我正在尝试分配一个对象数组,这些对象既不是可复制的,也不是可赋值的,也没有默认的构造函数。对象具有在运行时确定的参数。我知道你可以通过使用一个指针数组或巧妙地使用placement new来解决这个问题,但我更感兴趣的是,如果可以用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
生成一个工作线程并在最初构造的对象的this
的上下文中执行,任何使用移动构造函数的尝试都将破坏正在执行的线程的状态。
答案 0 :(得分:4)
如果您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);
}
(如果你声明了一个复制构造函数,即使该声明删除它,编译器也不会自动生成任何特殊的移动成员,因此你需要明确地请求它们)
这基本上归结为“阵列新布局”策略,但所有这些都被抽象为高级概念。
如果无法使用可移动类型,则必须实现类似向量的类,该类预先分配存储并且永远不会重新分配。标准库中没有类似的东西。
答案 1 :(得分: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;
};
答案 2 :(得分:3)
既不可复制也不可移动,也没有默认构造函数的类不能保存在标准容器中(不符合要求)或可变大小的数组分配(只允许固定数字的参数规范)元素)。
这意味着您需要分配原始内存并使用placement 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_;
};