我目前正在学习C ++。我学习了一些由编译器生成的特殊成员函数。
我知道每个成员函数的功能。但我想知道哪些成员函数是必要的,应该声明(而不是由编译器生成),作为良好编码实践的一部分,记住记忆和效率。
答案 0 :(得分:1)
但是我想要哪些成员函数是必要的并且应该被声明(而不是由编译器生成)
如果隐式生成的特殊成员函数执行您想要的操作,则不应显式声明它们。
如果某些其他生成的特殊成员函数没有按照您的意图执行,那么您必须明确声明它们,并提供所需的实现。
如果对[析构函数,复制/移动构造函数/赋值]中的任何一个有明确的非平凡定义,那么根据经验,您可能需要为每个定义定义。
答案 1 :(得分:1)
默认构造函数是这些中的一个特例。如果某些成员变量需要的初始状态不是这些成员的默认值,请编写默认构造函数。
如果您知道自己需要,其余部分应该被覆盖。
在某些合理的情况下,您可能希望编写列出的函数的自定义版本:
每个用例的示例包括:
std::shared_ptr
。如果一个类满足太多这些要求,您应该考虑更改设计以使用标准库提供的实用程序中的更多容器。特别是如果一个类需要第四个属性和其他三个属性中的任何一个。与第1-3点和第4点相关的责任应由不同的类别处理。 重要的是要注意,一个庞大,昂贵的创建资源和许多资源的所有权的所有权是不同类型的责任。
参考文献:
答案 2 :(得分:0)
默认构造函数是这里奇怪的人。你是否有一个默认构造并不一定与你是否编写其他构造有任何关系(尽管在实践中编写一个没有默认构造函数的移动构造函数可能很难)。
在大多数情况下,您应该尝试遵循零规则(http://en.cppreference.com/w/cpp/language/rule_of_three,http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/),这意味着您不会为您的班级编写任何这些成员函数。相反,选择正确表达各种资源所需的所有权语义的成员。成员std::vector
以您希望的方式正确处理复制和移动,因此具有此类成员的类不一定需要任何特殊成员。但是,如果您尝试使用使用new[]
创建的原始指针作为数组,那么您将需要处理许多这些问题,并且需要编写特殊的成员函数。
如果你需要写一个,你应该明确地考虑所有这些,但这并不意味着你必须写所有这些。有时您可能需要=default
或=delete
其中一些。一个简单的例子:
template <class T>
copy_ptr {
copy_ptr() = default;
copy_ptr(copy_ptr&&) = default;
copy_ptr& operator=(copy_ptr&&) = default;
copy_ptr(const copy_ptr& other)
: m_resource(make_unique<T>(*other.m_resource)
{}
copy_ptr& operator=(const copy_ptr& other) {
m_resource = make_unique<T>(*other.m_resource);
}
// define operator*, etc
std::unique_ptr<T> m_resource;
};
这是一个指针,它不像unique_ptr
那样是不可复制的,而是对它所拥有的对象进行深度复制。但是,我们能够从unique_ptr
“按原样”使用默认构造函数,移动运算符和析构函数,因此我们默认了它们。我们只重写了复制操作,做了最少的工作。
基本上,C ++中使用特殊运算符的想法是将它们“向下”推送到较小的对象/类中。通常全权负责管理该资源。协调业务逻辑的更大的类应该非常努力地将资源管理问题推迟给成员。