C++ 在结果中看不到析构函数更改的全局变量
我在一个网站上看到了以下程序,我无法理解其输出。 现在i是一个全局变量,在调用返回main之前,销毁a应该将其更改为10。有人建议,在调用返回main之后会发生A的销毁,但是作为调用方,当我调用函数时,我总是希望结果是最终的。这里函数返回值不是10而是3C++ 在结果中看不到析构函数更改的全局变量,c++,C++,我在一个网站上看到了以下程序,我无法理解其输出。 现在i是一个全局变量,在调用返回main之前,销毁a应该将其更改为10。有人建议,在调用返回main之后会发生A的销毁,但是作为调用方,当我调用函数时,我总是希望结果是最终的。这里函数返回值不是10而是3 我的问题是,为什么我会看到这一点,破坏到底是在哪里发生的。评估的顺序不是你所期望的。调用函数时,函数的参数可以按任意顺序求值,甚至可以交错。所以如果你打电话 f( g(), h(), i() ); 调用g()、h()和i()的顺序由编译器决
我的问题是,为什么我会看到这一点,破坏到底是在哪里发生的。评估的顺序不是你所期望的。调用函数时,函数的参数可以按任意顺序求值,甚至可以交错。所以如果你打电话
f( g(), h(), i() );
调用g()
、h()
和i()
的顺序由编译器决定。这也适用于运营商。当你有一个表达式的形式
expr1 << expr2 << expr3 << expr4;
expr1析构函数在对return
语句中的表达式求值后运行。如果是另一种情况,你会陷入困境:
std::string f() {
std::string res = "abcd";
return res;
}
此函数应返回包含“abcd”
的字符串对象,而不是已销毁的字符串对象的副本
为什么我看到了这一点,破坏到底在哪里被称为
我相信当实例超出范围时会调用实例析构函数。您可以通过以下方式对其进行测试(通过控制实例的范围——请参见下面的bar())
注意-为了减少混淆,1)重命名全局,2)当foo或bar被称为w.r.t.后继cout时显式控制
int g; // uninitialized!
class A
{
public:
~A()
{
g=10;
}
};
int foo()
{
g=3;
A ob;
return g;
} // <<<<<<<<<<< ob destructor called here
int bar()
{
g=3;
{
A ob;
} // <<<<<<<<<<< ob destructor called here
return g;
}
int t272(void)
{
g = 0; // force to 0
std::cout << "\n 1) Before calling foo g is " << g;
int fooRetVal = foo(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after foo, g = " << g
<< "\n 3) fooRetVal = " << fooRetVal
<< "\n 4) and now g = " << g
<< std::endl;
g = 0; // force to 0
std::cout << "\n 1) Before calling bar g is " << g;
int barRetVal = bar(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after bar, g = " << g
<< "\n 3) barRetVal = " << barRetVal
<< "\n 4) and now g = " << g
<< std::endl;
return (0);
}
int g;//未初始化!
甲级
{
公众:
~A()
{
g=10;
}
};
int foo()
{
g=3;
产科医生;
返回g;
}//返回i代码>你有UB,因为你没有序列点。顺便说一句,作为调用者,当我调用函数时,我总是希望结果是最终的——你返回的是i
的值,而不是指向i
@Jarod42的引用或指针。实际上没有UB,更像是意外的行为,但至少没有什么问题。
((expr1 << expr2) << expr3) << expr4;
<<
/ \
<< expr4
/ \
<< expr3
/ \
expr1 expr2
std::string f() {
std::string res = "abcd";
return res;
}
int g; // uninitialized!
class A
{
public:
~A()
{
g=10;
}
};
int foo()
{
g=3;
A ob;
return g;
} // <<<<<<<<<<< ob destructor called here
int bar()
{
g=3;
{
A ob;
} // <<<<<<<<<<< ob destructor called here
return g;
}
int t272(void)
{
g = 0; // force to 0
std::cout << "\n 1) Before calling foo g is " << g;
int fooRetVal = foo(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after foo, g = " << g
<< "\n 3) fooRetVal = " << fooRetVal
<< "\n 4) and now g = " << g
<< std::endl;
g = 0; // force to 0
std::cout << "\n 1) Before calling bar g is " << g;
int barRetVal = bar(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after bar, g = " << g
<< "\n 3) barRetVal = " << barRetVal
<< "\n 4) and now g = " << g
<< std::endl;
return (0);
}
1) Before calling foo g is 0
2) after foo, g = 10
3) fooRetVal = 3 <<< dtor called after return of foo
4) and now g = 10
1) Before calling bar g is 0
2) after bar, g = 10
3) barRetVal = 10 <<< dtor was called before return of bar
4) and now g = 10