C++ 为什么我可以使用非常量变量来接收常量函数

C++ 为什么我可以使用非常量变量来接收常量函数,c++,C++,我正在测试的这段程序的结果对我来说没有意义: class CC { public: int a; CC(); CC(int a); ~CC(); }; CC::CC() { this->a = 0; } CC::CC(int a) { this->a = a; } CC::~CC() { } const CC f() { CC cc(2); cout << &cc << endl

我正在测试的这段程序的结果对我来说没有意义:

class CC {
public:
    int a;
    CC();
    CC(int a);
    ~CC();
};

CC::CC() {
    this->a = 0;
}

CC::CC(int a) {
    this->a = a;
}

CC::~CC() {

}

const CC f() {
    CC cc(2);
    cout << &cc << endl;
    return cc;
}

int main() {
    CC cc = f();
    cc.a = 3;
    cout << &cc << " " << cc.a << endl;
}


result: // note the address are the same
0x7ffdd24b26e0
0x7ffdd24b26e0 3
为什么我可以在main中使用非常量变量来接收常量返回值函数

因为函数的返回值被复制到变量cc中。制作常量对象的非常量副本没有什么错;它不允许您修改常量对象


请将您想知道的任何其他问题作为单独的问题重新发布。

如果您不能在an=的右侧使用常数,则CC.a=3;这是违法的。那太疯狂了。使用常数的值当然是合法的——你还会用常数做什么

至于返回堆栈值,则返回该值。在执行返回时,该值定义良好。对象稍后不再存在并不重要,因为您已经返回了它的值

int foo()
{
    int i = 3;
    return i;
}
这里我们返回i的值,也就是说,我们返回3。这没什么错

int& foo()
{
    int i = 3;
    return i;
}
这里我们返回对i的引用。但我已经不存在了。这不好。

FWIW,const CC的返回值与CC相同

鉴于:

struct CC {};

const CC f() {
    return {};
}
g++4.9.3生成的汇编代码与为以下各项生成的汇编代码完全相同:

struct CC {};

CC f() {
    return {};
}
PS

这可能是在标准的某个地方指定的,我无法很快找到。

参考:


这两个地址相同的原因是因为RVO。因此,main中的变量'cc'在语义上仍然是f中的局部变量的副本。由于它只是原始对象的副本,因此将常量返回值指定给非常量变量是有意义的。

为什么我可以实际返回堆栈值?-因为你是按值返回的,它是你返回的任何东西的副本。这是java和C++值语义之间的另一个重要区别。CC类名使它们在与小写CC(与cout相同)组合时燃烧。停止:请删除不相关的代码,即几乎所有代码。如果是副本,为什么f中的变量地址与main中的变量地址相同?@darklord这是一个编译器优化。@darklord副本恰好与原始地址相同。这里没有问题,因为副本和原始文件不同时存在;这是正确的。如果我们将其更改为return int*,则需要return&i;。两者都是未定义的行为。@darklord将按值返回指向i的指针。这很好,因为该值将继续存在,但是您不能取消对指针的引用。@Kevin返回指向不再存在的对象的指针是不合适的。您甚至可以将该指针与NULL或nullptr进行比较,或者将其转换为布尔值。你就是不能去引用它,对吧。我的意思是取消对指针的引用。但是,没有好的代码应该返回指向局部变量的指针。
struct CC {};

CC f() {
    return {};
}