如果我想使类不可复制,"operator="返回类型是否重要?
Does "operator=" return type matter if I want to make the class non-copyable?
>假设我有一个不支持成员复制的类,所以我不想保留编译器实现的复制构造函数和赋值运算符。我也不想实现这些,因为
- 这样做需要额外的努力,我不需要在我的课堂上或
- 这些操作在我的课堂上没有意义
所以我想禁止他们。为此,我将声明它们是私有的,并且不提供任何实现:
class NonCopyable {
private:
NonCopyable( const NonCopyable& ); //not implemented anywhere
void operator=( const NonCopyable& ); //not implemented anywhere
};
现在我可以为成员函数选择任何返回类型operator=()
。我选择哪种返回类型有关系吗?
不,返回类型无关紧要。 †
C++ 标准不会对您自己声明的复制赋值特殊成员函数的返回类型施加任何要求。它只需要是一个operator=()
,接受"恰好一个类型为X
、X&
、const X&
、volatile X&
或const volatile X&
的参数"。††因此,void operator=( const NonCopyable& );
仍然是复制赋值运算符(具体来说,是用户声明的运算符(。
由于您实际上提供了自己的复制赋值运算符,因此它将抑制默认复制赋值运算符的生成。这会强制对 NonCopyable
的复制赋值运算符的所有调用解析为您的,从而导致任何使用复制赋值运算符的尝试都无法编译,因为它被声明为 private
。
class Foo : NonCopyable
{
};
int main()
{
Foo a;
Foo b;
// Compiler complains about `operator=(const NonCopyable&)`
// not accessible or something like that.
a = b;
}
而且由于我永远无法实际使用它,因此它不完全是规范的复制赋值运算符并不重要。如果我尝试使用复制赋值运算符,则会导致编译器错误,这正是您想要的。
† 当然,从风格上讲,复制赋值运算符是否真的做了某事,这确实很重要。通常,您希望操作员的行为与内置运算符一样,因此在实际执行分配时,返回X&
是一种很好的做法。
†† C++ 标准:12.8 复制类对象 [class.copy]
9 用户声明的复制赋值运算符
X::operator=
是类X
的非静态非模板成员函数,只有一个 类型X
、X&
、const X&
、volatile X&
或const volatile X&
的参数。
不,因为您永远不会在代码中调用此运算符。我倾向于保留返回类型NonCopyable&,以保持清晰和一致性。
这很重要:
-
void
确保来自类实现中的一小部分意外/误导调用(a = b = c/f(d = e((产生编译时错误而不是链接时错误,这可以节省编译时间并且更容易理解(与许多开发人员接触的大型类的相关性最小,其中一些开发人员先前熟悉程度有限(。 -
void
会为我(希望是大多数开发人员(敲响警钟,想知道您是否:- 想要删除默认生成的
operator=
- 只是懒得额外的打字,或者 不
- 熟悉/漠不关心
operator=
普遍预期的语义。
- 想要删除默认生成的
考虑到悬而未决的问题,其他程序员不太可能出现并认为您只是没有提供实现并随便添加它(您可能觉得注释就足够了(。
- 返回对类型的引用可能会使整个函数签名更易于即时识别,或者直观地搜索复杂类型以查找可能产生相反效果
operator=
- 所有这些都在旁观者的眼睛(和头脑(中。
不,因为你可以从 operator=
返回任何内容,即使你定义了它的实现。
不,没关系,因为你从不实现return
语句。如果尝试调用运算符,编译器将无法找到实现(具有任何return
类型,因此返回类型无关紧要(。
有趣的是,boost::noncopyable
的复制赋值运算符被声明为返回一个const noncopyable&
,但我想这只是约定。
- 如何获取std::result_of函数的返回类型
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 函数作为模板参数,是否对返回类型强制约束
- C++中函数的向量返回类型引发错误
- 检查函数返回类型是否与STL容器类型值相同
- 为什么返回类型中需要typename?C++
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 推导 std::vector::back() 的返回类型
- 在 c++ 中将函数返回类型指定为模板参数
- 使用 SWIG 更改生成的 CS 函数中的返回类型
- 为什么返回类型 std::reverse_iterator::operator[] 未指定
- 如何为 operator[] 指定返回类型
- 如果我想使类不可复制,"operator="返回类型是否重要?