C++:允许临时对象调用非常量成员函数的设计理念是什么?

c++: what's the design philosophy of allowing temporary object to call non-const member function?

本文关键字:函数 成员 设计理念 是什么 常量 非常 临时对象 调用 C++      更新时间:2023-10-16

我搜索堆栈溢出,人们说修改临时对象很愚蠢,所以不允许将临时对象绑定到非常量左值引用,就像你不能将临时对象传递到具有非常量左价值引用的函数一样。

那么,为什么临时对象被允许调用非常数成员函数,而该函数有可能修改对象并做"愚蠢"的事情呢?你可能会说,"哈,这是允许的,因为我们想为程序员提供一些灵活性,让他们做一些"愚蠢"的事情,而这些事情实际上并没有那么愚蠢",这就是我很难相信的原因,因为如果我相信这个借口,我认为"将临时绑定到非常值引用"也可以用同样的理由来证明。

谢谢!我在这里几乎找不到任何相关的问题。他们只是告诉我这是一个例外,但我们为什么允许这个例外?

您不能将临时引用绑定到非常量引用,但这里的基本原理是而不是,以避免意外修改临时引用。其基本原理是,您不想默默地错过修改您想要进行修改的内容。

假设它是允许的,那么:

void foo(double& x);
int y;
foo(y); //user wants to modify y, but instead a temporary is modified

就其本身而言,修改临时对象是完全可以的,而且通常很有用。没有理由拒绝它。

假设您有一个工厂方法,按照建议返回unique_ptr

std::unique_ptr<MyClass> createObject();

但是,您需要一个指向已创建对象的共享指针。所以你写

std::shared_ptr<MyClass> mySharedObject{createObject().release()};

您刚刚在一个临时对象上调用了一个非常量方法。我觉得它很有用。

好的。我忘记了shared_ptr构造函数接受unique_ptr。然而,为什么禁止快速读取文件的第一行?

std::array<char, 140> line;
std::istream{"MyFile.txt"}.readline(line, line.size()-1);

也许更有趣的是,为什么禁止将非常量左值引用绑定到临时值?对左值参数的非常量引用表示输出参数。由于转换,允许绑定到临时会导致微妙的错误。例如

void readShort(short & out)
{
out = 7;
}
long var;
readShort(var);

创建了一个临时short以匹配函数参数类型。现在禁止将其绑定到引用。如果允许,函数将分配给临时,然后结果将被丢弃。

更新

您能解释一下为什么不允许将临时对象绑定到本地非常量左值引用吗?

现在有一组规则用于将引用绑定到对象,无论是在函数调用期间还是在本地引用定义期间。根据上下文创建两组不同的规则会使语言复杂化(已经非常复杂(,需要一些理由。我想目前还并没有人提出这样的修改要求来说服标准委员会。

只是一些加法:不允许将临时绑定到本地非常量左值引用的原因。

首先,请阅读我接受的答案。

然后,如果允许将临时绑定到本地非常量左值引用,则可以编写如下代码:

void foo(double& x);
int& ref = 1;
foo(ref);

这是有问题的,原因与我接受的答案相同。

好的,我在这里放了一些额外的材料。以下材料引用自David Vandevoorde,Nicolai M.Josuttis,Douglas Gregor-C++Templates_ The Complete Guide Addison Wesley(2017(C.2.1成员函数的隐含论证

"旧的特殊情况允许右值绑定到左值对非常量类型的引用,而该引用是传统的隐含*此参数">

struct S{
void f1() {}//the old rule
void f2() && {}
void f3() & {}
};
int main()
{
S().f1();//Here, I THINK const this is bound to non-const, thus allowing calling non-const member functions.(the comment here is not quoted from the book.)
S().f2();
S().f3();//not okay
return 1;
}

使用-std=c++11编译选项。因此,这意味着C++设计者已经意识到,允许具有隐式const this*的临时对象调用非常数成员函数的旧规则并不那么好。因此,在C++11中,他们引入了&&&后缀函数声明。

但是,当谈到允许临时对象调用非常量成员函数的旧规则的设计哲学时,我认为不值得深究。C++11已经努力"修正"了这一点。(或者让程序员控制它。(