我有一个看起来像这样的课程:
class PasswordCategory
{
public:
PasswordCategory(const std::string&);
~PasswordCategory();
PasswordCategory() = delete;
...
}
这会导致与分配器相关的编译器错误:
错误C2280:' PasswordCategory :: PasswordCategory(void)' :尝试 引用已删除的函数
文件:xmemory0:577
IDE是VS 2013社区。 p>
我假设这是因为其他地方我正在使用这些类别的矢量。
std::vector<PasswordCategory> m_categories;
我只使用emplace_back(string)将元素插入其中,但是,似乎PasswordCategory的默认分配器正在尝试使用PasswordCategory的默认构造函数,但由于删除了它,因此会抛出错误。
如果我提供默认构造函数,一切正常,但我想知道如果没有默认构造函数我可以如何缓解这个问题,如果有的话?
我想到了以下解决方案:
我想知道我是否可以某种方式禁止无法构建我的班级,同时仍然可以按标准容器中的值使用它?
感谢任何答案和见解,提前谢谢。
P.S。这是我正在做的一个小项目,以便更好地理解C ++,我试图避免大多数常见的陷阱,并尽可能使一切尽可能可靠,这样当我打算开展更大的项目时,我会更容易避免这些常见的陷阱。我试着以不同的方式提出问题,但没有找到我的问题的答案,所以相反,我问自己的问题。
答案 0 :(得分:3)
std::vector
本身并不要求T
成为DefaultConstructible
类型:
直到C ++ 11:
T必须符合CopyAssignable和CopyConstructible的要求。
自C ++ 11以来:
对元素施加的要求取决于对容器执行的实际操作。通常,要求元素类型是完整类型并满足Erasable的要求,但许多成员函数强加了更严格的要求。
有关详细信息,请参阅this page。
但是,您可以对容器执行操作,这涉及创建隐式实例以及导致此错误的原因。如果你可以跟踪它们并消除它们,那么一切都应该可以正常工作,因为如果不使用默认构造函数就不需要它。
考虑您的建议:
1。为我的类提供构造我的类的自定义分配器。
这不会有帮助 - std::allocator
不对默认构造元素负责,因为它根本没有定义这样的功能。请参阅std::allocator::construct。
修改强> 这里有点小错误,我没有注意到C ++ 11中的小变化:
直到C ++ 11
void construct( pointer p, const_reference val );
自C ++ 11以来
template< class U, class... Args >
void construct( U* p, Args&&... args );
2. 提供默认构造函数,只使用一些参数调用我的其他构造函数。
这也没有解决这个论点是非选择性的问题,并且不应该被默认。 这也不是完全便携的。一些编译器(如VC11)不支持委托构造函数。
3. 使用引用或指针的向量而不是值向量。
这似乎是最合理的解决方案,但它引入了手动管理内存的需要,除非我们使用unique_ptr或类似的东西。 不太有效 - 您无法创建引用容器。最接近的解决方案是容器,它包含std::reference_wrapper个。原始/智能指针的容器也是一种选择,但这是重点,事情开始变得混乱。
此外,在您的原始代码中,没有必要声明已删除的默认构造函数 - 如果您声明任何构造函数,则表示没有默认构造函数(除非您定义它)并且编译器赢了& #39; t生成任何。
答案 1 :(得分:1)
原则上,你不能:标准容器要求包含的对象是可默认构造的。 (见Mike Seymour的评论)。
原则上你应该能够,除非你在内部使用需要默认构造的操作。
也就是说,你可以简单地创建一个空构造函数(默认成员为sane /调用带有一些参数的另一个构造函数)。如果正确编写客户端代码,则不会遇到使用默认值初始化的对象。
需要默认构造对象的操作通常是调整大小,还有一些需要创建内部对象的操作(即除非您想要保留元素并使用它而不显式初始化它,否则您应该没有问题)。 / p>