C++ trivial和non-trivial构…

本文探讨了C++中POD类型及其trivial函数的概念,并解释了这些概念如何影响类的操作效率。通过对比trivial与non-trivial函数,阐述了STL如何利用这些特性来优化内存操作。

今天看书看到侯捷的《STL源码剖析》里提到trivial和non-trivial及POD类型,查了些资料理解了一下。

trivial意思是无意义,这个trivial和non-trivial是对类的四种函数来说的:

  • 构造函数(ctor)
  • 复制构造函数(copy)
  • 赋值函数(assignment)
  • 析构函数(dtor)

如果至少满足下面3条里的一条:

  1. 显式(explict)定义了这四种函数。
  2. 类里有非静态非POD的数据成员。
  3. 有基类。

那么上面的四种函数是non-trivial函数,比如叫non-trivial ctor、non-trivial copy…,也就是说有意义的函数,里面有一下必要的操作,比如类成员的初始化,释放内存等。

那个POD意思是Plain Old Data,也就是C++的内建类型或传统的C结构体类型。POD类型必然有trivial ctor/dtor/copy/assignment四种函数。


//整个T是POD类型
class T
{
    //没有显式定义ctor/dtor/copy/assignemt所以都是trivial
    int a; //POD类型
};

//整个T1是非POD类型
class T1
{
    T1() //显式定义了构造函数,所以是non-trivial ctor
    {}
    //没有显式定义ctor/dtor/copy/assignemt所以都是trivial
    int a;//POD类型
    std::string b; //非POD类型
};

那这有什么用处呢?

如果这个类都是trivial ctor/dtor/copy/assignment函数,我们对这个类进行构造、析构、拷贝和赋值时可以采用最有效率的方法,不调用无所事事正真的那些ctor/dtor等,而直接采用内存操作如malloc()、memcpy()等提高性能,这也是SGI STL内部干的事情。

比如STL的copy算法最基本的想法是这样的:


// 非POD重载指针数值
template <</span>class T> void copy(T* source, T* destination, int n, __false_type)
{
    // 省略异常处理
    for (; n > 0; n--,source++,destination++)
    {
        // 调用source的复制构造函数
        constructor(source, *destination);
    }
}

// POD重载指针数值
template <</span>class T> void copy(T* source, T* destination, int n, __false_type)
{
    // 省略异常处理
    memmove(source, destination, n);
}

当然实际的copy比这个复杂多了,有非常多的特化等,这个只是其中一方面而已。

`clazy-unused-non-trivial` 是 Clazy 工具中的一项静态代码检查规则,用于检测未使用的非平凡类型(non-trivial type)变量。该警告通常出现在 Qt 项目中,当声明了一个具有复杂类型的局部变量但从未使用时触发。非平凡类型指的是那些具有造函数、析函数或需要进行资源管理的类型,例如 `QString`、`QList`、`QMap` 等。 ### 警告原因 此类警告的根本原因是代码中存在冗余或无用的变量声明,这不仅浪费了内存资源,还可能影响程序性能,特别是在循环体或高频调用的函数中。例如: ```cpp void processList() { QList<QString> names = {"Alice", "Bob", "Charlie"}; } ``` 在此例中,变量 `names` 被声明并初始化,但从未被访问或操作,因此编译器会提示 `clazy-unused-non-trivial` 警告[^2]。 ### 解决方法 1. **删除未使用的变量** 如果变量确实不需要参与任何逻辑运算,可以直接将其删除,以保持代码简洁高效。 2. **添加注释说明用途** 如果变量是为了调试目的而保留,可以添加注释说明其用途,或者使用 `(void)` 强制转换来抑制警告: ```cpp void processList() { const QList<QString> names = {"Alice", "Bob", "Charlie"}; (void)names; // 用于调试,防止编译器警告 } ``` 3. **重代码逻辑** 如果变量本应被使用但由于某些原因被遗漏,则需要修复逻辑错误,并在适当的地方引用该变量。 4. **配置 Clazy 忽略特定情况** 如果确定某段代码中的未使用变量是安全且必要的,可以通过 `.clazy` 配置文件或 IDE 设置禁用特定行或函数的此项检查。 ### 示例修复 假设以下代码触发了警告: ```cpp void exampleFunction() { QString tempString = "Temporary Data"; } ``` 修复方式如下: ```cpp void exampleFunction() { // 若变量仅用于调试,可添加注释或强制转换 const QString tempString = "Temporary Data"; (void)tempString; } ``` 如果变量实际应被使用,则补充相关逻辑: ```cpp void exampleFunction() { const QString tempString = "Temporary Data"; qDebug() << "Data:" << tempString; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值