类成员数组的对象没有默认构造函数和删除复制导引器初始化 [英] Class member array of objects without default constructor and deleted copy contructors initialization
问题描述
我有一个名为Container的类,其中必须存储类DontCopyMe的三个(在编译时已知)对象。 DontCopyMe类具有非默认构造函数和删除的拷贝构造函数。如何初始化Containter?
I have a class called 'Container' in which three (known at compile time) objects of class DontCopyMe must be stored. Class DontCopyMe has non-default constructor and deleted copy constructors. How can I initialize Containter?
示例代码:
#include <string>
class DontCopyMe
{
public:
DontCopyMe(const unsigned int SomeInt, const std::string & SomeString): SomeInt(SomeInt), SomeString(SomeString)
{
}
DontCopyMe(const DontCopyMe &) = delete;
DontCopyMe & operator = (const DontCopyMe &) = delete;
DontCopyMe(DontCopyMe &&) = delete;
DontCopyMe & operator = (DontCopyMe &&) = delete;
private:
const unsigned int SomeInt;
const std::string SomeString;
};
class Container
{
public:
Container(): Array{{1, "A"}, {2, "B"}, {3, "C"}}
{
}
private:
DontCopyMe Array[3];
};
int main()
{
Container C;
return 0;
}
当然我会得到:
Of course I'm getting:
main.cpp: In constructor 'Container::Container()':
main.cpp:22:56: error: use of deleted function 'DontCopyMe::DontCopyMe(DontCopyMe&&)'
Container(): Array{{1, "A"}, {2, "B"}, {3, "C"}}
推荐答案
clang ++ 3.6.2
编译您的代码。 g ++ 5.2.0
不。
clang++ 3.6.2
compiles your code. g++ 5.2.0
does not.
这是一个(讨厌的解决方法:使用 std :: aligned_storage
, placement new
和显式析构函数调用:
Here's a (nasty) workaround, for the moment: use std::aligned_storage
, placement new
and explicit destructor calls:
#include <type_traits>
class Container
{
private:
using Storage = typename std::aligned_storage
<
sizeof(DontCopyMe),
alignof(DontCopyMe)
>::type;
public:
Container()
{
// Construct an instance of `DontCopyMe` in the memory
// location starting at `&Array[0]`.
new (&Array[0]) DontCopyMe{1, "A"};
// ...
new (&Array[1]) DontCopyMe{2, "B"};
new (&Array[2]) DontCopyMe{3, "C"};
// You can also (and should) use a for-loop.
}
~Container()
{
// Interpret the bytes at location `&Array[2]` as if
// they were a `DontCopyMe` instance, then call the
// `~DontCopyMe()` destructor on it.
(reinterpret_cast<DontCopyMe*>(&Array[2]))->~DontCopyMe();
// ...
(reinterpret_cast<DontCopyMe*>(&Array[1]))->~DontCopyMe();
(reinterpret_cast<DontCopyMe*>(&Array[0]))->~DontCopyMe();
// You can also (and should) use a for-loop.
}
private:
Storage Array[3];
};
您必须为 Containers
正确清理对齐的存储。您可能想要将所有 aligned_storage
相关代码包含在辅助类中。
You'll have to implement move and copy operations for Containers
that cleanup the aligned storage properly. You may want to wrap all aligned_storage
-related code in an helper class.
你提到你需要更多的安全性和稳定性。实现这个的最好的方法是在一个帮助类中包装 std :: aligned_storage
,这将确保你不犯错误。
You mentioned you require additional safety and constness. The best way to achieve this is wrapping std::aligned_storage
in an helper class that will make sure you don't make mistakes.
以下是一些让你开始使用的代码:
Here's some code to get you started:
#include <type_traits>
#include <utility>
#include <cassert>
template<typename T, std::size_t TSize>
struct ASImmutableArray
{
private:
using ThisType = ASImmutableArray<T, TSize>;
using Storage = typename std::aligned_storage
<
sizeof(T),
alignof(T)
>::type;
Storage data[TSize];
template<typename... Ts>
void initAt(std::size_t mIndex, Ts&&... mXs)
{
assert(mIndex >= 0 && mIndex < TSize);
// assert the data was not initialized
new (&data[mIndex]) T(std::forward<Ts>(mXs)...);
}
void deinitAt(std::size_t mIndex)
{
assert(mIndex >= 0 && mIndex < TSize);
// assert the data was actually initialized
reinterpret_cast<T*>(&data[mIndex])->~T();
}
public:
// ...
};
一个想法是传递 std :: tuple
在 ASImmutableArray
的构造函数中创建实例,并使用 placement new 创建
T
code>通过扩展元组并将它们的内容转发到 T
的构造函数,以正确的索引。元组将包含与构建 T
所需的类型相同的类型。
An idea is passing std::tuple
instances in the constructor of ASImmutableArray
, and creating T
instances in place using placement new
at the correct indices by expanding the tuples and forwarding their contents to T
's constructor. The tuples would contain the same types as the types required to construct T
.
您还可以跟踪初始化/ deinitialized items with an additional member boolean array(可以在发布版本中禁用,只用于在开发过程中验证类的正确用法)。
You can also keep track of initialized/deinitialized items with an additional member boolean array (that can be disabled in release builds, and only used for verifying the correct usage of the class during development).
想要类似的(旧)实施的示例,这是我写的一个我的图书馆。
If you want an example of an (old) implementation of something similar, this is something I've written for one of my libraries.
您还可以查看我写了这个标记的联合实现看到一个例子,我如何使用调试的成员变量没有额外的安全发行版本的开销。
You can also check out this tagged union implementation I've written to see an example on how I use debug-only member variables that have no overhead in release-builds for additional safety.
这篇关于类成员数组的对象没有默认构造函数和删除复制导引器初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!