当一个string变量作为左值接收函数返回,当函数没有正确返回时,该string变量被如何构造?

请看如下代码:

#include

#include

using namespace std;

string foo()

{

if(0)

{

return "you get";

}

}

int main(int argc, char **argv)

{

string ret = foo();

if (ret == "")

{

cout << "ret == \"\"\n";

}

if (ret.empty())

{

cout << "ret is empty\n";

}

cout << "main end\n";

return 0;

}

输出:

main end

Segmentation fault (core dumped)

这里的变量ret接收函数foo()的返回,但函数条件未全覆盖导致没有返回。

它的运行结果没有输出ret == "",也没有输出ret is empty, 也就是ret 并不是ret == "",也不是empty,并且发生了段错误。

错误原因猜测

这个段错误导致的原因是什么?

很明显string ret = foo()这里的ret变量调用的是一个重载赋值符的构造函数,这里会涉及到一个内存的拷贝。所以是对非法内存的拷贝引起的吗?还是Main函数析构时释放了一个非法的空间?

因为“main end” 已经打印出来了,所以该段错误应该是发生在析构时期,该段错误可以猜测为是对变量ret的析构导致,也就是ret没有正确构造使其指向了非法内存,这里只是猜测,因为手上暂时没有源码,猜测有待求证!!

该段代码编译时,我们会期待其输出警告“函数没有正确返回”之类,但实际没有警告,即使有警告,也不知道这里竟会发生段错误,这就是C++的缺陷与语法陷阱之一。

为了避免这种问题,编译时可以增加-Wall参数,输出所有警告。

举一反三

那么其他类型的返回值也会段错误吗?

像int等基础类型,不会导致段错误,会根据其构造原则返回随机值或者固定值。

其具体原因还有待深究!

#include

#include

using namespace std;

int foo(int i)

{

if(0 == i)

{

return 0;

}

}

int main(int argc, char **argv)

{

int ret = foo(0);

int ret2 = foo(100);

cout << "ret == "<

cout << "ret2 == "<

return 0;

}

输出:

ret == 0

ret2 == 0

总结:

当一个string变量作为左值接收函数返回,当函数没有正确返回时,该string变量没有正确构造,此时对其变量的访问可能会导致段错误。

为了避免这种语法陷阱,可采取以下的策略

有返回值函数,最后的返回语句不要放在if条件判断中,避免没有返回而编译器没有警告

编译时增加 -Wall 参数

对于自定义类,认真对待赋值构造函数,保证其正确构造和析构

非基础类型变量,最好不要作为函数返回的左值直接赋值构造

string ret = foo();

改为:

string ret;

ret = foo();