C++编程中需要注意的几点

C++编程之自定义日志类 ——log4cpp使用详解 C++编程之自定义日志类 ——log4cpp使用详解log4cpp简介与安装log4cpp安装log4cpp简单介绍layout布局——日志输出格式log4cpp::BasicLayoutlog4cpp::PatternLayoutappenderlog4cpp::FileAppenderlog4cpp::RollingFileAppenderlog4cpp::OstreamAppenderlog... 阅读详情

1、最好不要使用引用返回值

有同学在传递的参数的时候使用引用方式传递,避免了临时对象的创建,提高了效率,那么在返回值的时候能不能使用引用呢?

看如下代码


        class Rational{
        public:
            Raional( int numerator = 0, int denominator =1);
            ...
        private:
            int d, d;
            friend Rational operator* (const Rational& lhs, const Raional& rhs) ;
        };
       Rational Rational::operator* (const Rational& lhs,const Raionl&rhs)
        {
                return Rational  result(lhs.n*rhs.n,lhs.d*rhs.d);
        } 
    }
  这个类就是我们前面所介绍的有理数类。这里想想会发生一次类的构造与类的析构,那么如果使用引用就可以避免这个问题吗?达到提高效率吗?

  函数创建新对象有两种方法,一个是在栈(statck)中创建,一个是在堆(heep)中创建。

        People p(a,b)                  //栈中创建
        People *p = new People(a,b)   //堆中创建
 现在首先考虑在栈中创建,但是这个创建的变量是一个局部变量,会在退出函数之前销毁。

   const Rational& operator* (const Rational& lhs, const Rational & rhs)
        {
            Rational  result(lhs.n*rhs.n,lhs.d*rhs.d);
            return result;
        }
  在函数内以stack方式空间创建对象是局部对象,任何函数如果返回一个引用指向某个局部对象,都会发生错误。因为局部对象在函数退出之前被销毁了,意味着reference所指的对象不存在。
      于是考虑在堆中创建   const Rational& operator* (const Rational& lhs, const Rational & rhs)
        {
            Rational*  result=new Rational(lhs.n*rhs.n,lhs.d*rhs.d);
            return *result;
        }
  现在又发现了一个问题,new出来的对象由谁来delete?好这个问题先占时不考虑看下面情况

          Rational w,x,y,z;
          w=x*y*z;    
  这里同时一个语句调用了两次operator*,意味着new了两次,也就需要delete两次。但是这里没有合理的办法让opertaor*使用者进行那些delete调用,因为无法让使用者获取返回的指针,这将导致资源泄漏。
      于是考虑返回一个引用,其指向定义于函数内部的static Rational对象。
      const Rational & operator*(const Rational& lhs,const Rational & rhs)
        {
            static Rational result;
            result = ...;
            return result;
        }
那么显而易见就是多线程,在多线程环境下,这样写安全吗?好如果说不关多线程。那么如下代码会发生什么?


  bool operator == (const Rational& lhs, const Rational&  rhs);

    ...

    Raional a,b,c,d;
    if((a*b) == (c*d) 
    {
            ...
    }
    上述if语句表达式无论a,b,c,d为何值都是true,因为它们都指向同一个静态值。

 

2、最好不要将所有变量定义放在语句开头。

有同学可能上过C语言课程,喜欢学习C的,喜欢将所有的变量定义放在开头,但是在C++中,我建议最好不要这样做,因为定义一个变量时,程序便注定需要进行一次构造与析构。例如在下面程序:大概意思我们允许1米8以下并且年龄在60岁以下的同学买票进入。


 1 class People{...};
 2 class Ticket{...};
 3 bool Isvalid(const People&p){...}
 4 void Banding(const People& p,Ticket& t); 
 5 Ticket buyTicket(const People& p)
 6 {
 7     Ticket t;
 8     if(Isvalid(p)){ return NULL };
 9     //信息与票绑定
10     Banding(p,&t);
11     return t;
12 }
假如这里检测买票人条件不符合,那么就不能进入买票从而进行信息与绑定操作,那么这里Ticket t语句就让该函数白白承受了一次Ticket构造成本与析构的成本。
所以最好不要将变量提前定义,最好在要用到的时候定义,避免不必要的性能开销。上面例子改成下面这样即可: 
 1 class People{...};
 2 class Ticket{...};
 3 bool Isvalid(const People&p){...}
 4 void Banding(const People& p,Ticket& t); 
 5 Ticket buyTicket(const People& p)
 6 {
 7     if(Isvalid(p)){ return NULL };
 8     Ticket t;
 9     //信息与票绑定
10     Banding(p,&t);
11     return t;
12 }
 

3、最好不要做过多的类型转换

C++规则的设计目标之一是,保证“类型错误”绝不可能发生。理论上程序通过编译,就表示它并不企图在任何身上执行任何不安全,荒谬的操作。可惜类型转换破环了类型系统,它可能导致任何种类麻烦,有些非常麻烦。就例如本文最后一个代码例子。C和C++都支持隐形类型转换,同时C++有四种显示转换操作符。成员函数与非成员函数的抉择里有介绍。但是建议最好不要做过多的类型转换,能避免就避免。类型转换往往也不是按照你的意思,首先看一个例子:


 1 #include <iostream>
 2 
 3 class base
 4 {
 5     public:
 6         base():a(0),b(0){}
 7         base(const int& x,const int& y)
 8         :a(x),b(y){}
 9         virtual void init()
10         {
11             a=5;
12             b=5;
13             std::cout<<"in base a value is "<<a<<std::endl;
14             std::cout<<"in base b value is "<<b<<std::endl;
15         }
16         
17         int get_a() const
18         {
19             return a;
20         }
21         
22         int get_b() const
23         {
24             return b;
25         }
26     private:
27         int a;
28         int b;
29 };
30 
31 class derived:public base
32 {
33     public:
34         derived(int x,int y):base(x,y){}
35         void init()
36         {
37             static_cast<base>(*this).init();
38         }
39 };
运行结果为

in base a value is 5
in base b value is 5
a value is 2
b value is 2
这里将derived类型转化为base,但是调用base::init()函数并不是当前对象上的函数,而是早前转型动作所建立的一个"*this对象的base的副本,所以当我们尝试改变对象内容,其实改变的是副本内容,其对象内容并没有被改变。

 如何解决这个问题呢?我们可以直接声明调用基类的函数


 1 class derived:public base
 2 {
 3     public:
 4         derived(int x,int y):base(x,y){}
 5         void init()
 6         {
 7             //static_cast<base>(*this).init();
 8             base::init();
 9         }
10 };
运行结果为:

in base a value is 5
in base b value is 5
a value is 5
b value is 5
或许此时你记起来应该使用dynamic_case(如果看过以前的文章的话:它用于安全地沿着继承关系向下进行类型转换)。使用dynamic_cast直接出现错误。


 1 class derived:public base
 2 {
 3     public:
 4         derived(int x,int y):base(x,y){}
 5         void init()
 6         {
 7             //static_cast<base>(*this).init();
 8             //base::init();
 9             dynamic_cast<base*>(this)->init();
10         }
11 };
运行结果为:

段错误 ((主存储器)信息转储)
假设一个类有五层的单继承关系,如果在该对象上执行dynaic_cast,那么会有多达五次的strcmp调用,深度或者多重继承的越多,成本越高。之所以需要dynamic_cast是因为想在derived class对象上执行 derived class操作函数,但是目前只有一个指向base的指针或者引用,这个时候可以用它们来处理。

C++ 一个函数调用其他.cpp文件中的函数 使用VC或VS创建C++项目的时候,会自动产生许多文件夹,其中有一个文件夹->源文件: 在该文件下可以自定义许多.cpp文件,但是需要注意的是这里面的各个文件只能有一个文件中含有main()函数, 而且各个文件中不能使用相同的函数名进行定义; 那么要那么多文件放在项目中有什么用呢? 当然这里C++是提供一个文件调用其他文件中函数的功能的, 这就可以让我们自定义一个只包含main()... 阅读详情

相关推荐

【RabbitMQ C++】AMQP-CPP实战:从零构建高效消息队列系统

本文详细介绍了如何使用C++和AMQP-CPP库从零构建高效的RabbitMQ消息队列系统。内容涵盖环境搭建、核心概念解析,并通过实战代码示例演示了如何编写生产者和消费者程序,实现消息的发布与订阅。文章重点讲解了如何与libev事件循环集成,以构建高性能、可靠的异步通信组件,为C++分布式系统开发提供了一套完整的解决方案。

5f4d3s2a1q的博客 933

C++你最好不要做的

1、最好不要使用引用返回值 有同学在传递的参数的时候使用引用方式传递,避免了临时对象的创建,提高了效率,那么在返回值的时候能不能使用引用呢? 看如下代码 class Rational{ public: Raional( int numerator = 0, int denominator =1); ...

dkenp04020的专栏 185

C++学习:0、CPP 学习概述

目录一、汇编的重要性1、学习建议2、代码本质的挖掘3、编程语言的本质区别二、开发环境的搭建 路线大纲: 常用语法: 面向对象: 项目实战: 特点: 通过反汇编,通过底层来观察 C++ 的本质 CPP 的应用领域 思考一个问题:既然 C ++ 执行效率这么高,为什么还要出现新的编程语言?所有地方都用 C++ 不就好了吗? 首先每一门编程语言都有自己的优缺点,都有自己的擅长的领域。 比如 python 适合数学家来进行算法开发,适合分析师进行数据分析,如果让数学家和分析师再学习C++ 那就太

vincent3678的博客 7709

C++应尽量使用的特性和应避免的特性

来源:《C专家编程》 尽量使用的C++特性: 类。 构造函数和析构函数,但只限于函数体非常简单的例子。 重载,包括操作符重载和I/O。 单继承和多态。 避免使用的C++特性: 模板。 异常。 虚基类(virtual base class)。 多重继承。 就我个人而言,异常的简单使用也没问题,其它的都很赞成此书的看法。写过一年的C++,似乎也只用到了...

jubincn的专栏 183

Dev-Cpp.zip:C++ IDE的安装与使用指南

Dev-Cpp作为一款广受欢迎的集成开发环境(IDE),在C++编程社区拥有着悠久的历史。尽管它不是最现代的IDE工具,但在开发者中依然有着坚实的拥趸。Dev-Cpp的核心组件包括:MinGW编译器:用于编译C/C++源代码。集成开发环境(IDE):提供代码编辑、编译和调试等集成工具。项目管理器:方便用户组织和管理多个项目。用户界面:提供图形化的操作环境。Dev-Cpp提供广泛的个性化设置选项,开发者可以根据自己的喜好和工作习惯对IDE进行配置。

weixin_33750664的博客 815

c++实际编程中应该注意的一些问题

c++实际编程中应该特别注意的一些问题 ,讲的很详细,设计到的面很光,几乎涵盖c++的编程中设计到的所有问题,讲解很细致,容易懂。

盘点那些C++中在写大型程序中最好不要滥用的语法排行榜

盘点那些C++中在写大型程序中最好不要滥用的语法排行榜

jinboxin_的博客 359

(MATLAB)一维信号峰值检测findpeaks

一维信号波峰波谷检测,峰值、峰宽、到达时间计算。MATLAB自带的findpeaks函数能完成这一任务,在这里分享其基本用法与特殊用法。

HPC_ZY 2万+

平时写c++程序需要注意什么

记一些几年前写c++经常会犯的一些错误,想到了其他的后面再加上 1、变量、函数命名不规范。 如果一个变量命名随意,比如表示一个学生的年纪,如果这样定义int a;相信一个月后自己再看代码,都不知道a表示什么意思, 如果用int age; 来表示,就清晰很多了。 再说函数,如果需要一个连接数据库的函数,写成connect();这是connect什么呢。如果写成connectDatabase()就很清晰了。 2、传递指针没有判断是否为空。传递对象、变量没有判断是否有效。 如果有一个接口是 void

c_shell_python的博客 1058

从Unitree B2W到四足机器人:用Isaac Lab构建强化学习奖励函数的5个实战技巧

本文分享了在Isaac Lab仿真环境中,为Unitree B2W等四足机器人设计强化学习奖励函数的5个核心实战技巧。内容涵盖奖励函数的结构化组合、轮腿混合机器人的适配策略、课程学习的动态调整、域随机化增强鲁棒性以及高效的调试可视化方法,旨在帮助开发者构建更稳定、高效的机器人运动策略。

lg888的博客 1066

顶级的FDE需要拥有哪些技能?

上一篇《》说明白了什么是FDE。这一篇回答下一个问题:要成为顶级 FDE,需要哪些具体的技能?要想弄清楚FDE应该有哪些能力,就得先搞清楚FDE要完成哪些工作。同时,有一点是我们要密切关注的:现在是大模型时代,所以我们不能脱离大模型讨论FDE的能力。我们可以把FDE在客户现场需要完成的工作分为四类:破冰与诊断、价值交付、项目与预期管理、沟通与影响。另有两项元能力贯穿始终。以下按工作类别逐一拆解,每项能力配 1 / 3 / 5 分标准,方便对照自评。文末有完整打分工具链接。

mydeman的学习日志 261

C++程序设计及注意事项

指的是在同一个域中,用同一个函数名来定义多个函数,但其参数类型应有不同,编译器将通过实参和形参的类型、个数等确定最佳匹配调用,不同类函数不采用函数重载。//声明一个max函数,其返回类型为int,两个输入为a,b,其类型均为int。多人编辑同一个项目时,一般在前面加static,使其只在某特定文件中使用,而不是全局,避免两人采用了同一函数名报错。6.C++允许为形参指定默认值,如果调用时该形参变量未给定实参值,则使用该形参值,如果给定了,则采用实参值。//采用以下方式,可以将后面定义的变量,在前面使用。

doudou2weiwei的博客 421

使用PyTorch和TextCNN实现英文长文本诗歌文本分类

在这个过程中,我们了解了如何进行文本数据预处理、构建TextCNN模型,并进行训练与评估。首先,我们需要将文本文件加载到内存中,并将每个诗歌作为一个样本。然后,我们需要将每个样本转换为数字表示,这可以通过将词汇表中的每个词语映射到一个唯一的整数来实现。此外,我们还需要将每个样本的长度统一为固定值,以便于模型输入。通过这个示例,我们可以学习如何构建一个简单但有效的文本分类模型,并在具体的应用场景中进行训练和预测。该模型通过使用多个不同尺寸的卷积核来捕捉文本中的不同长度的信息,并通过最大池化操作提取关键特征。

loop_syntax648的博客 254

JavaScript和C++的一些显著差异和学习tips

JS转C++的学习tips

Nesb01t is here. 250

【优化求解】基于matlab粒子群算法PSO确定最佳开关角对称级联多层逆变器【含Matlab源码 13080期】

粒子群算法PSO确定最佳开关角对称级联多层逆变器 完整代码,包运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 97

25、量子计算:中性原子与约瑟夫森结量子比特

本文详细探讨了中性原子和约瑟夫森结两种量子比特在量子计算中的应用。中性原子量子比特利用光晶格实现量子态的操控,具有长相干时间的优势,但面临可扩展性和多量子比特操作的挑战;而约瑟夫森结量子比特基于超导技术,结合半导体制造工艺,具有低耗散和潜在的高可扩展性,但在参数控制和环境干扰方面存在难题。文章还比较了这两种方案的性能、应用场景及未来发展趋势,展望了它们在量子计算发展中的潜力与突破方向。

ol789012的博客 212

C++中.cpp和.hpp的区别

c++中 cpp和hpp 首先,我们可以将所有东西都放在一个.cpp文件内,编译器会将这个.cpp编译成.obj,即编译单元。一个程序可以由一个编译单元组成,也可以由多个编译单元组成。一个.cpp对应一个.obj,然后将所有的.obj链接起来(通过一个叫链接器的程序),组成一个.exe,即程序。如果一个.cpp要用到另一个.cpp定义的函数怎么办,只需在这个.cpp中写上它的函数声明。 链接器将所...

Qzx9059的博客 1万+

手把手教你学pcie--性能调优 - 中断机制优化

在PCIe系统开发中,中断机制是主机与设备之间通信的重要组成部分。然而,不当的中断设计可能导致CPU负载过高、延迟增加等问题。本文将详细介绍如何优化PCIe系统的中断机制,提升系统性能和响应速度。传统中断(INTx):通过专用引脚发送中断信号,可能引发冲突且效率较低。消息中断(MSI):通过内存写操作发送中断消息,避免冲突并提高效率。扩展消息中断(MSI-X):基于MSI改进,支持更多独立中断向量,适用于复杂场景。选择合适的中断模式对系统性能至关重要。

MHD0815的博客 291

从理论到实践:如何通过CPP-Crash-Course快速掌握C++编程技巧

**CPP-Crash-Course**是一个专为C程序员设计的C++快速入门教程项目,提供从基础语法到高级特性的完整学习路径。这个开源项目通过实用的代码示例和清晰的解释,帮助开发者快速从C语言过渡到现代C++编程,掌握面向对象编程、模板、异常处理等核心概念。无论你是刚接触C++的新手,还是希望系统复习C++知识的开发者,这个项目都能为你提供有价值的参考。 ## 📚 项目概述与核心价值 CP

gitblog_00617的博客 494

【AutoCAD中实现双击文本编辑功能】

例如:以下是官方博客例子浅析先加入相关的头文件和库文件。在AutoCAD中有一个很重要的功能,就是双击图形尺寸或文本后会出现一个文本编辑框,用户可在该编辑框中修改文字。本文介绍了如何使用AcEdInplaceTextEditor来实现该功能。实现cad的消息监听。创建一个消息监听的类并在cad中注册来实现消息监听。主要是监听键盘输入。提示:以下是本篇文章正文内容,下面案例可供参考提示:这里对文章进行总结:例如:以上就是今天要讲的内容,本文仅仅简单介绍了的函数和方法。

我的博客 1149

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C++改写成C需要注意的几点

1.注释问题,C语言中"//"注释是非法的,解决方法:换成/**/的形式 2.C语言中没有BOOL类型       可以用int型替换                      typedef int bool;                      #define true 1                      #define TRUE 1          

大胖子的程序梦 1561

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【CPP】C++模板:初阶到进阶语法与实用编程示例

探索C++模板的深度与广度,《C++模板:初阶到进阶语法与实用编程示例》带您从基础语法起步,逐步深入到高级特性。本博客结合精炼的理论知识和丰富的代码实例,揭示模板编程的精髓,助您提升开发效率,优化代码结构。无论您是初学者还是资深开发者,都能在这里找到提升C++编程技能的宝贵资源。

BinaryWiker的博客 1380

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

c++的.h和.cpp文件

.h文件是不对外隐藏的, .cpp文件在编译后对外隐藏---这是最本质的特点和区别 .h和.cpp文件本质上是没有什么区别的,.h文件实现的功能是声明本文件或.cpp文件中需要被别人使用或知道的变量、类型、函数及宏定义等。.h文件就像是一个接口,具体的实现可以在.cpp中也可以在.h中。.cpp中的函数或变量即便是全局的,在没有其他.cpp文件使用的情况下,也可以不写在.h中。 下面参考:h...

小白博客 1万+

C++ 编程环境搭建与实践 —— 基于 comp-cpp 开源项目

C++ 编程环境搭建与实践 —— 基于 comp-cpp 开源项目 项目介绍 comp-cpp 是一个致力于简化 C++ 开发者编程环境配置的开源工具。它提供了便捷的方式让开发者快速搭建 C++ 开发环境,无论是对于初学者还是经验丰富的开发者,都能通过这个项目快速上手,进行代码编译与运行。该项目在 GitHub 上托管,允许社区成员贡献和改进,以适应更广泛的需求。 GitHub 仓库地址: htt...

gitblog_00367的博客 1150

关于C++语句的几点注意事项

关于C++语句的几点注意事项 main函数名的注意事项 int main()表明main()函数的返回值是整形,并将该值传送给调用它的函数,但是main()函数不会从调用它的函数获得任何信息。很多程序使用古典的C语言的函数名来代替: main()   //原来C语言的类型 在最初的C语言里,忽略返回值和说明该函数属于整形类型是同一个道理。但是,C++废除了这种用法。我们也可以使用下面这种变

u013252950的专栏 526

YOLOs-CPP:一个免费开源的YOLO全系列C++推理库(以YOLO26为例)

Python、Pytorch、C++、人工智能、Ultralytics、YOLO、ONNX、图像分类、目标检测、实例分割、旋转框检测、姿势估计

FriendshipTang的博客 2301
上一篇: C++文件依存关系
下一篇: C中的static修饰的镜头变量含义
myLogs
博客等级 码龄14年 6粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值