我刚遇到一个提出问题的错误:
我在成员函数中,并通过const&
- 参数将成员变量传递给另一个成员函数。被调用的函数是非const
。
如果我考虑一下,我很确定我不应该这样做。
危险在于,const&
参数可能会在被调用函数中神奇地改变,而它偶然会修改最初传入的成员变量。允许,而不是声明const
。
代码中的示例:
struct S
{
void caller()
{
called_one(this->memvar);
}
void called_one(const int& x)
{
// ...
this->memvar = 2; // changes x! That's surprising... at least for this function
// ...
}
private:
int memvar{};
}
我认为不小心再碰到那个错误会很好。 对于语言或编译器来说,防范这种情况可能不是最简单的任务吗? 我还没有在一些流行的指南来源中遇到过这个问题。
更新:
也许我应该澄清一点,我发现这种行为并不奇怪。我不知道为什么别名变量会发生变化。
如果答案只集中在called_one
发现奇怪而不是我自己的函数上,那将是很好的。)
更新:
...... caller
就是那个,做错了什么。
但我认为他很有可能实现这一点(通过阅读代码)。他将别名传递给他知道被调用函数也可以修改的东西(不是通过传递的参数)。这可能会导致被调用函数内出现意外行为。
所以,即使在这种特殊情况下,编译器也无法或不合理地提供帮助,我不明白为什么以指南的形式引入这个陷阱是不值得或没用的。
答案 0 :(得分:4)
您的问题等同于定义
f(int& x, const int& y) { x = 2; }
然后致电
f(x, x);
修改第二个参数x
,没有任何警告。您刚刚在两个参数之间创建了一个别名。因此,如果您的调用修改了第一个参数,它也会修改第二个参数。
编译器无法知道变量之间的所有别名信息。它的工作只是为所有可能的别名提供正确的代码。由于调用尊重签名,编译器不应发出任何警告。
更新:
在语言层面没有指导方法可以防止 这种未定义的行为。别名可能会占用很多 形式。例如,函数可以修改数据结构 (树,列表,矢量)从一个主动的根源 它的元素。然后从根,你可以达到 元素和意外修改元素或更糟糕的 支持。正如你所说,这是程序员的责任 要小心这些要点。
编译器可以查看参数并检测两个参数是否属于具有相同类型和不同const信息的(普通)别名。但有时候程序员想要这样的行为而没有任何警告;例如:
void mul_assign(double& x, const double& y) { x *= y; }
void sqr_assign(double& x) { mul_assign(x, x); }
答案 1 :(得分:0)
您的代码完全合法,就像更简单的
int x = 0;
const int &x_r = x; // x_r can't be changed directly
x = 42; // also changes (the value referenced by) x_r
我通常会认为你的代码设计不好(但没有上下文就很难说,为什么要这样做)。
如果你想在你的情况下避免使用别名,只需按值传递x
(至少假设它不是更大的结构):
void called_one(const int x) // x is guaranteed not to change
{ ... }
答案 2 :(得分:0)
此代码是合法的,因为您要修改downcast_mut
,而不是int
。对于const指针,引用可以被认为是改进的语法糖。这意味着您的代码行为如下:
const int&
(注意:void called_one(const int *const x) // const pointer to const int
{
memvar = 2;
}
适用于左侧的元素,除非它在开头 - 然后它适用于右侧的元素。)
const
指向x
。因此,在修改memvar
时,会修改memvar
个点。 x
本身未已修改且无法被修改,同样x
无法修改,因为它是*x
。与参考文献相同。
但是没有理由const
会使原始值本身不可修改。它只表示您无法在此处使用const
修改x
。
另请注意,您可以将x
拒绝为int&
,这很好。但你也可以使用const_cast
将其强制转换为const int&
(如果你不删除初始类型中的int&
!!其他,那就是UB)
const