【编程】C++语言编程规范-2

这篇具有很好参考价值的文章主要介绍了【编程】C++语言编程规范-2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

编程实践

结合C++ Effective系列参考树、尤其是工程经验教训的总结。

并发

  • 除非必要,尽量少用线程。
  • 多线程编程要守护好内存,使用atomic、mutex、condition variable、future、semaphore、latch、barrier等同步机制避免数据竞争。
  • 尽量缩小临界区,临界区指独占的资源,禁止其他线程访问变量的代码片段,如持有mutex的作用域。与回调函数相似,应尽可能精简此类操作,避免执行耗时的处理、阻塞性操作如sleep。能在临界区、回调函数外处理的,尽可能在外部。
  • 必须正确管理多线程中的对象,避免某线程正在访问的对象被另一线程清理,如用move方法使对象从一个线程正确移交给另一个线程,避免内存泄漏。
  • 使用condition variable时,必须增加条件判断并在循环中等待。下例中,线程ReceivingUnPro中条件变量错过了通知,缺少条件判断,就始终处于等待状态,而ReceivingPro依靠while判断条件,解决了问题。
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

std::condition_variable g_dataCond;
std::string g_words = "";
std::mutex g_mtx;
bool g_isReady = false;

void ReceivingUnpro() {
    std::unique_lock<std::mutex> lg(g_mtx);
    std::cout << "waiting!" << std::endl;
    g_dataCond.wait(lg);
    std::cout << "Bad receiving thread got the message: " << g_words
              << std::endl;
}
void ReceivingPro() {
    std::unique_lock<std::mutex> lg(g_mtx);
    while (!g_isReady) {
        g_dataCond.wait(lg);
    }
    std::cout << "Protected receiving thread got the message: " << g_words
              << std::endl;
}
void Sending() {
    std::lock_guard<std::mutex> lg(g_mtx);
    g_words.append("Go forward!");
    g_isReady = true;
    g_dataCond.notify_all();
}
int main() {
    std::thread b(Sending);
    b.join();
    std::thread ap(ReceivingPro);
    ap.join();
    std::thread a(ReceivingUnpro);
    a.join();
    return 0;
}

理论上,条件变量有虚假唤醒问题,所以要条件判断避免。

  • 用std::lock_gaurd、std::unique_lock确保锁被释放,不要用std::mutex的lock()、unlock()以免遗忘或异常导致dead lock。
    错误的例子,
#include <mutex>
std::mutex x;
{
    x.lock();
    // 处理数据的代码
    // 发生异常,导致后面未执行
    x.unlock(); 
}

下例中出现dead lock,文章来源地址https://www.toymoban.com/news/detail-833455.html

#include <unistd.h>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

using std::cout;
using std::endl;
using std::lock_guard;
using std::mutex;
using std::chrono::seconds;

mutex m1, m2, m3;
std::condition_variable cnd;
std::mutex dt_mtx;
bool ready = false;
std::vector<int> vec_i;

void ProcessData() {
    for (const auto i : vec_i) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

void T1F() {
    std::unique_lock<std::mutex> lock(dt_mtx);
    cnd.wait(lock, [] { return ready; });
    ProcessData();
}

void T2F() {
    {
        std::lock_guard<std::mutex> lock(dt_mtx);
        for (int i = 0; i < 10; i++) {
            vec_i.push_back(i);
            sleep(1);
        }
        ready = true;
    }
    cnd.notify_all();
}

void Fun1() {
    lock_guard<mutex> l1(m1);
    std::this_thread::sleep_for(seconds(1));
    lock_guard<mutex> l2(m2);
    std::this_thread::sleep_for(seconds(1));
    cout << "Fun1 is finishing" << endl;
}
void Fun2() {
    lock_guard<mutex> l1(m2);
    std::this_thread::sleep_for(seconds(1));
    lock_guard<mutex> l2(m3);
    std::this_thread::sleep_for(seconds(1));
    cout << "Fun2 is finishing" << endl;
}
void Fun3() {
    lock_guard<mutex> l1(m3);
    std::this_thread::sleep_for(seconds(1));
    lock_guard<mutex> l2(m1);
    std::this_thread::sleep_for(seconds(1));
    cout << "Fun3 is finishing" << endl;
}
int main() {
    std::thread t1(Fun1);
    std::thread t2(Fun2);
    std::thread t3(Fun3);
    if (t1.joinable()) {
        cout << "t1 is joining" << endl;
        t1.join();
    }
    if (t2.joinable()) {
        cout << "t2 is joining" << endl;
        t2.join();
    }
    if (t3.joinable()) {
        cout << "t3 is joining" << endl;
        t3.join();
    }
#ifdef VERSION1
    std::thread t1(T1F);
    std::thread t2(T2F);
    t1.join();
    t2.join();
#endif
    return 0;
}

对象与内存管理

  • 避免访问越界,如索引数组前判断下标是否超出数组区间。
  • 申请内存要先检查大小。
  • 数组作为函数参数,若是已知的固定长度,建议用std::array;若不确定长度,传递来的数组表现为指针,则函数参数要加上数组长度,或者将数组的指针与长度封装为一个类。
  • 避免函数返回其局部变量的地址,建议改为返回复制的值。
  • lambda的作用范围超出局部时,如用于线程等,按引用捕获可能导致局部变量过早被清理,应改为按值捕获;应明确捕获的变量、合理的捕获类型。

常量

  • 建议优先用constexpr定义常量,编译时硬编码变量,提升效率;改关键字要求被修饰对象在编译时可确定变量的值。
  • 使用const修饰函数内部不会修改的参数,类内不变的变量、不修改不可变的成员变量的成员方法。
  • const实例化的对象,只允许调用其const方法。

到了这里,关于【编程】C++语言编程规范-2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 使用C++编写自己的编程语言CASM

    CASM帮助文档: CASM解释器讲解视频: 我独自开发了一种编程语言:CASM CASM解释器源代码(剪贴板有问题,总是粘贴成一行,哪位大佬帮帮我……): #include iostream #include cstring #include string #include cstdio #include map #include queue #include stack #include cstdlib #include list #include \\\"hint.hpp\\\" us

    2024年02月10日
    浏览(6)
  • 编程语言比拼之Java VS C++

    编程语言比拼之Java VS C++

    学Java还是C++?   Java和C++都是非常受欢迎的编程语言,各有各的优势和适用场景。以下是对它们的简要比较: 性能:C++通常被认为是一种更高效的编程语言,适用于对性能要求较高的应用程序,如游戏开发、嵌入式系统和高频交易等。C++具有更接近底层的控制能力,允许开发

    2024年02月13日
    浏览(5)
  • C#编程语言的优势与C++对比

           C#语言是由 C/C++演变而来的,是微软推出的一种基于.NET框架的、面向对象的高级编程语言。以.NET框架类库作为基础,拥有类似Visual Basic的快速开发能力。简单易学,入门超快,减少了烦人的指针,有统一的操作符/修饰符/运算符,使用起来极其舒心。         对于

    2024年02月09日
    浏览(4)
  • C++ 编程入门指南:深入了解 C++ 语言及其应用领域

    C++ 是一种跨平台的编程语言,可用于创建高性能应用程序。 C++ 是由 Bjarne Stroustrup 开发的,作为 C 语言的扩展。 C++ 为程序员提供了对系统资源和内存的高级控制。 该语言在 2011 年、2014 年、2017 年和 2020 年进行了 4 次重大更新,分别为 C++11、C++14、C++17 和 C++20。 C++ 是世界上

    2024年03月21日
    浏览(10)
  • 中文编程开发语言工具构件说明:屏幕截取构件的编程操作

    中文编程开发语言工具构件说明:屏幕截取构件的编程操作

    屏幕截取 用于截取指定区域的图像。 图    标: 构件类型:不可视 重要属性 l        截取类型 枚举型,设置在截取屏幕时的截取类型。包括:全屏幕、指定区域、活动窗口三种。当全屏幕截取时相当于执行了硬拷屏(PrintScreenSysRq键)功能;指定区域截取则是通过矩形

    2024年02月07日
    浏览(5)
  • [编程语言][C++][Qt]单独添加UI文件

    [编程语言][C++][Qt]单独添加UI文件

    不知什么原因,Qt Creator并不是很完美很智能。当先写好界面类的头文件和源代码文件后,我们再添加用于可视化界面设计的UI文件时,会出现一些问题。 当使用CMake管理项目时,CMake会读取 CMakeLists.txt 文件来确定各种项目设置。需要把 MainWindow.ui 包含进项目时,在 CMakeLists.

    2024年02月07日
    浏览(5)
  • 中文编程开发语言工具编程实际案例:美发店会员管理系统软件编程实例

    中文编程开发语言工具编程实际案例:美发店会员管理系统软件编程实例

    中文编程开发语言工具编程实际案例:美发店会员管理系统软件编程实例 中文编程开发语言工具编程实际案例:美发店会员管理系统软件编程实例。 软件功能: 1、系统设置:参数设定,账号及权限设置,系统初始化,卡类型设置,积分清零等。 2、会员信息登记:可以刷卡

    2024年02月07日
    浏览(6)
  • 最短路径算法的编程与实现 C语言

    最短路径算法的编程与实现 C语言

    1.掌握最短路径算法的基本原理及编程实现; operating system version:Win11 CPU instruction set:  x64 Integrated Development Environment:Viusal Studio 2022 1)建立一张图,选择一种存储结构(邻接矩阵或邻接表)初始化该图; 2)用Dijkstra算法实现点与点之间的最短路径。 1) 实现图的两种表示方法;

    2024年02月11日
    浏览(3)
  • 掌握Go语言:Go语言递归函数,解密编程之谜,探索算法的奥秘!(27)

    递归函数是指在函数内部调用自身的函数。在Go语言中,递归函数使用起来非常方便,但需要注意递归的终止条件,以避免无限循环。 Go语言递归函数的使用方法 在Go语言中,编写递归函数的基本步骤如下: 上述三点内容详细解释如下: 定义一个函数,函数内部调用自身 :

    2024年04月15日
    浏览(31)
  • day3 驱动开发 c语言编程

    通过ioctl(内核+应用层) 控制led灯三盏,风扇,蜂鸣器,小马达 头文件head.h 内核代码 ioctldev.c 应用层代码 ioctl.c

    2024年02月16日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包