当有人写了
时template <typename T> class Container;
当你有一个const Container<const MyType>
时,很明显会发生什么(好吧,假设你知道const {对MyType
的意义)。你不能改变任何东西 - 不对结构重新排序,不添加或删除元素,不改变现有元素;如果某些内容确实发生了变化(例如mutable
),你应该看另一种方式,因为它不算数。
Container<MyType>
你的意思也很清楚 - 一切都是可变的(除了可变的classeses中的const成员等)。
在将constness与非constness混合的地方,事情会变得混乱。使用const Container<MyType>
- 期望修改MyType
元素是否合理?如果容器的状态取决于它们的值,该怎么办?另外,如果我有
using Stuff = Container<MyType>;
然后传递const Stuff
个参数。这种不透明的措辞让你质疑你是否“应该”改变东西元素中的任何东西;毕竟,你不能在const
上说“深Stuff
而不在那里触摸任何东西”。没有人喜欢写作:
using ConstStuff = Container<const MyType>;
然后传递尴尬的const ConstStuff
。然而,std容器完全(?)能够与const
生活在一起但不适合自己的元素。
甚至Container<const MyType>
的语义都会造成某种语义障碍:你可以删除容器中的项目;你可能需要能够复制它们。这不会产生非常const
y元素。
最后,当你有多个模板化类型参数时,事情变得更加混乱。假设现在是
template <typename K, typename V> class Container;
(是的,它就像一个std::map
,这是这个问题的动力。)有了这个,你可以拥有一个恒定的容器但是可变的键 - 荒谬,对吧?你可以通过改变它们来搞砸它。或者,假设它是一个具有const
个键但非const
值的容器,并假设它通过不保留相同值的多个副本来最小化存储,而是指向该值的单个副本。然后你就来改变这个价值。
在这些情况下,是否存在某种关于const语义的约定或经验法则?
注意:我特意忽略了指针,您也可以在答案中忽略它们(如果您愿意,也可以忽略它们。)
答案 0 :(得分:1)
这个问题更适合programmers.stackexchange.com,但没关系。
如果某些内容确实发生了变化(例如可变),你应该看看另一种方式,因为它不算数。
不,某些事情可能合法地改变。因为这个const Container
可能只是一个由你特别不可修改的接口,而实现它的人可能已经为自己保留了随意修改它的自由,这非常好。无论是谁将const Container
交给您,都可以这样做,以便不必实例化新容器,也不必为自己的非const容器的内容制作安全副本。
在将constness与非constness混合的地方,事情会变得混乱。使用const容器 - 期望修改MyType元素是否合理?
嗯,是的。那是正是为什么它是const Container<MyType>
而不是const Container<const MyType>
。 完全合理。
如果容器的状态取决于它们的值,该怎么办?
好的,那就是事情会让人感到困惑。但这真的很奇怪。 (而这通常发生在真正奇怪的事情上:它们开始变得混乱。)
即使Container的语义也会造成某种语义障碍:你可以删除容器中的项目;你可能需要能够复制它们。这不会构成非常常见的元素。
不,元素是完全consty,因为通过从const对象复制来初始化实例正是复制构造函数所做的,并且因为从容器中删除对象并不意味着需要对其执行任何操作对象,即使该对象是从容器中删除的结果,也可以调用const对象的析构函数。
最后,当你有多个模板化类型参数时,事情变得更加混乱。假设它现在是
template <typename K, typename V> class Container;
(是的,它就像一个std :: map,这是这个问题的一个推动者。)有了这个,你可以有一个常量的容器但是可变的键 - 太荒谬了,对吗?
是的,那会有点荒谬。但是语言必须为您提供使用不可变键和可变值声明容器的能力,因此语言必须提供完成此类操作所需的功能。
除了密切关注constness之外,我不知道该提出什么建议。