工作中遇到的C++语言基础和常见错误

简介: ## C++历史及标准 这里简单列一下```C++```发展进程中的几次重大事件以及我常使用的典型特性,各个标准支持的具体细节可参阅ISO标准文档。 - ```C With Classes```:支持C++基础语言特性,包括多态、异常处理、模板、命名空间等 - ```C++98```:STL、RTTI、模板、异常处理及其它标准库实现 - ```C++03```:修复C++98中的缺

C++历史及标准

这里简单列一下C++发展进程中的几次重大事件以及我常使用的典型特性,各个标准支持的具体细节可参阅ISO标准文档。

  • C With Classes:支持C++基础语言特性,包括多态、异常处理、模板、命名空间等
  • C++98:STL、RTTI、模板、异常处理及其它标准库实现
  • C++03:修复C++98中的缺陷及支持TR1
  • C++11:auto、range-for、rvalue、lambda、shared_ptr、concurrent
  • C++14:变量模板、多态lambda及增强的库实现
  • C++17:折叠表达式、类模板实参推导
  • C++20:<=>、协程、概念

参数传递与返回值

  • 避免产生临时变量导致冗余性能开销
int setupMVAudioStream(std::string path);                    // BAD
int setupMVAudioStream(std::string const& path);    // GOOD
  • 返回值为类对象时确定使用RVO特性
// 如果此时函数体实现编译器未使用RVO,则会出现冗余性能开销,BAD
std::list<MVStreamOption*> generateMVStreamList(std::list<MVStreamOption*> *optionList);

// 使用引用传递参数返回结果,不会出现冗余性能开销,GOOD
void generateMVStreamList(std::list<MVStreamOption*>& outList,
                          std::list<MVStreamOption*> *optionList);
  • 函数具有返回类型时需明确给出返回值,避免外部使用错误的返回值或者函数无法正常执行结束
int EditorService::updateRenderStreams(FileStreamList &streamList)
{
    // 执行一些操作,没有return语句或者存在多个可能无法执行到的非全局生存期return语句
    if (condition)
    {
        return -1;    // 当condition为false时不执行
    }
    // BAD
}

// 始终应该存在一个函数内全局生存期的return语句,避免其它非全局生存期的return语句未执行
int EditorService::updateRenderStreams(FileStreamList &streamList)
{
    // 执行一些操作,可能存在多个多生存期管理的return语句
    if (condition)
    {
        return -1;    // 当condition为false时不执行
    }
    return 0;    // GOOD
}
  • 返回类成员变量时应该返回引用或者常量引用或者指针
// BAD,调用unordered_map的拷贝构造函数导致额外性能开销
std::unordered_map<Node*, int> Node::GetActiveChildren()
{
    return mActiveChildren;
}

// GOOD,返回引用和常量引用,不会产生临时对象
std::unordered_map<Node*, int>& Node::GetActiveChildren()
{
    return mActiveChildren;
}
std::unordered_map<Node*, int> const& Node::GetActiveChildren() const
{
    return mActiveChildren;
}

基类声明虚析构函数避免产生内存泄漏

struct Base {  // BAD: implicitly has a public nonvirtual destructor
    virtual void f();
};

struct D : Base {
    string s {"a resource needing cleanup"};
    ~D() { /* ... do some cleanup ... */ }
    // ...
};

void use()
{
    unique_ptr<Base> p = make_unique<D>();
    // ...
} // p's destruction calls ~Base(), not ~D(), which leaks D::s and possibly more

构造和析构函数中避免调用虚函数

class Base {
public:
    virtual void f() = 0;   // not implemented
    virtual void g();       // implemented with Base version
    virtual void h();       // implemented with Base version
};

class Derived : public Base {
public:
    void g() override;   // provide Derived implementation
    void h() final;      // provide Derived implementation

    Derived()
    {
        // BAD: attempt to call an unimplemented virtual function
        f();

        // BAD: will call Derived::g, not dispatch further virtually
        g();

        // GOOD: explicitly state intent to call only the visible version
        Derived::g();

        // ok, no qualification needed, h is final
        h();
    }
};

优先使用初始化列表而不是赋值构造对象

class B {   // BAD
    string s1;
public:
    B(const char* p) { s1 = p; }   // BAD: default constructor followed by assignment
    // ...
};

class C {   // UGLY, aka very bad
    int* p;
public:
    C() { cout << *p; p = new int{10}; }   // accidental use before initialized
    // ...
};

class D {   // Good
    string s1;
public:
    A(string_view v) : s1{v} { }    // GOOD: directly construct
    // ...
};

使用auto作为返回类型推导时增加cv修饰避免产生临时变量

std::unordered_map<Node*, int> const& Node::GetActiveChildren() const
{
    return mActiveChildren;
}

// BAD: 此时children类型实际为std::unordered_map<Node*, int>,退化为采用模板类型推导没有cv属性
auto children = node->GetActiveChildren();

优先使用emplace接口替换push/insert提高性能

std::list<std::string> ls;
std::string s("abc");

ls.push_back(s);                        // BAD
ls.push_back(std::move(s));    // GOOD

ls.push_back("abc");                // GOOD
ls.emplace_back("abc");            // BETTER

使用make_unique/make_shared构造智能指针管理对象

// Not exception-safe: the compiler may interleave the computations of arguments as follows:
//
// 1. allocate memory for Foo,
// 2. construct Foo,
// 3. call bar,
// 4. construct unique_ptr<Foo>.
//
// If bar throws, Foo will not be destroyed, and the memory-allocated for it will leak.
f(unique_ptr<Foo>(new Foo()), bar());    // BAD

// Exception-safe: calls to functions are never interleaved.
f(make_unique<Foo>(), bar());    // GOOD

使用empty代码size判断STL容器是否为空

std::list<int> ls;
// ...

// BAD: 不同的STL标准实现稍有差异,比如Android下的list.size的时间复杂度为O(N)
if (ls.size() > 0)
{
    // ...
}

// GOOD:时间复杂度为O(1)
if (!ls.empty())
{
    // ...
}

总结

C++有很多特性,上述只是列出了极小一部分使用过程中经常出现问题的一些用法,比如导致崩溃或者内存泄漏等,以及可以使用性能更高的一些建议,更多的用法将在后续逐渐总结出来。

目录
相关文章
|
3月前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
76 2
|
3月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
82 0
|
1月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
129 5
|
1月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
37 5
|
1月前
|
存储 编译器 C语言
深入计算机语言之C++:类与对象(上)
深入计算机语言之C++:类与对象(上)
|
1月前
|
存储 分布式计算 编译器
深入计算机语言之C++:C到C++的过度-2
深入计算机语言之C++:C到C++的过度-2
|
1月前
|
编译器 Linux C语言
深入计算机语言之C++:C到C++的过度-1
深入计算机语言之C++:C到C++的过度-1
|
2月前
|
JavaScript 前端开发 测试技术
一个google Test文件C++语言案例
这篇文章我们来介绍一下真正的C++语言如何用GTest来实现单元测试。
21 0
|
3月前
|
编译器 C++ 容器
C++语言的基本语法
想掌握一门编程语言,第一步就是需要熟悉基本的环境,然后就是最重要的语法知识。 C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。 对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。对象是类的实例。 类 - 类可以定义为描述对象行为/状态的模板/蓝图。 方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。 即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。 完整关键字
|
4月前
|
前端开发 编译器 程序员
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
下一篇
无影云桌面