首页 > 编程语言 >C++陷阱—指定的返回类型的函数实际没有返回时会发生什么

C++陷阱—指定的返回类型的函数实际没有返回时会发生什么

时间:2024-04-12 15:48:14浏览次数:20  
标签:返回 string int ret C++ 时会 foo 函数

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

请看如下代码:

#include <iostream>
#include <string.h>

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 <iostream>
#include <string.h>

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 == "<<ret<<endl;
    cout << "ret2 == "<<ret2<<endl;
     
    return 0;
}

输出:

ret == 0
ret2 == 0

总结:

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

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

  1. 有返回值函数,最后的返回语句不要放在if条件判断中,避免没有返回而编译器没有警告
  2. 编译时增加 -Wall 参数
  3. 对于自定义类,认真对待赋值构造函数,保证其正确构造和析构
  4. 非基础类型变量,最好不要作为函数返回的左值直接赋值构造
 string ret = foo();
 改为:
  string ret;
  ret = foo();

标签:返回,string,int,ret,C++,时会,foo,函数
From: https://www.cnblogs.com/HuangLiDi/p/18131437

相关文章

  • C++编译器对溢出的默认处理
    C++编译器对溢出的默认处理在算数运算中,有一个比较头疼又必须要处理的事情:“溢出”,当我们有所疏忽,没有对溢出的情况做处理时,在我们不知情下就会产生很诡异的bug!那么当我们没有做溢出处理时,编译器的默认处理方式是什么呢?下面我们探究一下这个问题。测试环境Linux4.15.0#16.0......
  • C++观察者模式的实现
    C++观察者模式的实现观察者模式介绍观察者模式是软件设计模式里面一种很常用又很重要的一种设计模式,观察者模式又叫做发布-订阅(Publish/Subscribe)模式。也就是主题对象(subject)发布通知,订阅该主题的多个观察者(observer)可以收到通知从而更新自己。主题对象Subject发出通知时并不......
  • C++陷阱 — C++ auto变量类型推导
    问题描述C++使用auto类型声明一个单例对象的引用时,通过该auto变量来访问单例,是否等同于使用单例类::Instance()来访问单例呢?试看如下的例子:#include<stdint.h>#include<iostream>#include<string>#include<map>usingnamespacestd;classSingleClass{public:......
  • 统一controller返回对象
    统一controller返回对象packagecom.xxx.jscaffold.handler;importcom.xxx.jscaffold.api.dto.common.Result;importorg.springframework.core.MethodParameter;importorg.springframework.http.MediaType;importorg.springframework.http.converter.HttpMessageConver......
  • String类型转LPCTSTR -----理解C++中的字符串类型转换
    在看代码时,发现有时候会把string类型转换为LPCTSTR,刚开始不理解为什么要做这个转换,所以做了一些调查,现在记录如下是这样的,STRING是代表C++中的字符串string,而LPCTSTR代表的是Windows系统中的字符串类型。也就是说,这样转换的目的是为了把C++中的字符串string转换为Windows系......
  • 火狐浏览器看视频全屏时会黑一下屏幕
    火狐浏览器看视频全屏时会黑一下屏幕在浏览器地址栏输入:“about:config”(不包含引号,下同)并回车,然后点击“我知道了”,可以进入高级设置界面。在地址栏下方的搜索栏中输入:“full-screen-api.transition-duration”,首选项中出现两项设置,分别双击并把数值修改为“00”(注意中......
  • 2022年蓝桥杯C++B组国赛-试题D-最大数字
    0.题目问题描述给定一个正整数N。你可以对N的任意一位数字执行任意次以下2种操作:将该位数字加1。如果该位数字已经是9,加1之后变成0。将该位数字减1。如果该位数字已经是0,减1之后变成9。你现在总共可以执行1号操作不超过A次,2号操作不超过......
  • C++——线性动态规划
    线性动态规划引入:1.爬楼梯爬楼梯类型的问题可谓是线性DP的入门题目以及经典中的经典。我们先来看一下题目。爬楼梯题目描述有一天,三萩实在太无聊了,竟然无聊到去数台阶了。有一个楼梯一共有m级,刚开始三萩在第一级,他就想,若每次只能跨上一级或者二级,要走上m级,共有多少种走法?......
  • C++ 引用和指针:内存地址、创建方法及应用解析
    C++引用和指针创建引用引用变量是对现有变量的“别名”,它是使用&运算符创建的:stringfood="Pizza";//食物变量string&meal=food;//对food的引用现在,我们可以使用变量名food或引用名meal来引用食物变量:cout<<food<<"\n";//输出Pizzacout<<mea......
  • python基础-函数(函数参数、返回值、执行、传参、作用域、函数名)
    前言!!!注意:本系列所写的文章全部是学习笔记,来自于观看视频的笔记记录,防止丢失。观看的视频笔记来自于:哔哩哔哩武沛齐老师的视频:2022Python的web开发(完整版)入门全套教程,零基础入门到项目实战1.初识函数函数就是一大堆代码的集合,这一堆的代码再起个名字。#定义函数def函数名......