为何std::slice_array赋值运算符为const?复合运算符却非const?
这是个特别细致的问题,正好戳中了C++标准库代理类设计的微妙之处!咱们一步步来理清楚:
首先得搞明白,std::slice_array是个代理类——它自己不存储数据,只是持有原数组的指针、切片的步长和长度这些元信息,相当于数组某段切片的“引用”。
当你调用它的operator=时,你修改的是它指向的原数组里的元素,而不是slice_array对象自身的元数据(比如指针、步长这些)。而C++里const成员函数的核心承诺就是不修改对象自身的状态,这里的“自身状态”指的是代理类自己持有的元数据,而非它引用的外部元素。既然赋值操作根本不会改动这些元数据,把operator=设为const完全符合语义,非常合理。
这确实有点反直觉——毕竟复合赋值同样只是修改引用的元素,不会动代理类自身的状态。主要原因大概有这两点:
和普通对象的行为保持一致
你想啊,普通的内置类型或者自定义类,复合赋值(比如int& operator+=(int&, int))都是非const的,还会返回自身的非const引用,用来支持链式调用(比如a += b += c)。标准库设计代理类的时候,可能希望它尽可能贴近普通对象的使用习惯,哪怕从const正确性的角度看它其实可以是const,还是延续了这个传统。历史兼容的考量
std::slice_array从C++98就存在了,当时的标准库设计更看重和已有编程习惯兼容,没抠那么极致的const正确性。后来的标准修订也没改这一点,毕竟要是突然把复合赋值改成const,说不定会破坏一些依赖非const引用返回的老代码。
还有个小细节:slice_array::operator=返回的是void,而复合赋值返回slice_array&。这也能看出设计上的权衡——赋值操作没必要支持链式调用(毕竟a = b = c对切片来说语义不太清晰),但复合赋值保留了这个能力,那就得返回非const引用,自然成员函数不能是const了。
内容的提问来源于stack exchange,提问作者xskxzr

