整数溢出问题
当变量存储的值超出其数据类型范围时发生。例如,short 类型(通常为 -32768 到 32767)赋值为 40000 会导致未定义行为。
解决方法

  • 使用范围更大的类型(如 intlong long)。
  • 启用编译器警告(如 GCC 的 -Wconversion)。
  • 运行时检查边界条件。

浮点数精度误差
浮点数(float/double)无法精确表示某些十进制数(如 0.1),导致累计误差。
解决方法

  • 需要高精度时使用 decimal 库(非标准)或固定点数方案。
  • 比较浮点数时应使用误差范围而非直接相等:
    const double epsilon = 1e-9;
    if (abs(a - b) < epsilon) { /* 视为相等 */ }
    

类型转换问题

隐式类型转换陷阱
混合类型运算时编译器自动转换可能导致意外结果。例如:

int a = 5;
double b = 2;
int c = a / b; // 实际得到 2 而非 2.5

解决方法

  • 显式强制转换:static_cast<double>(a) / b
  • 启用编译器警告(如 -Wsign-conversion)。

有符号与无符号不匹配
比较或有符号/无符号混合运算时易出错:

unsigned int u = 10;
int i = -5;
if (i < u) { // 结果为 false,因 i 被隐式转为无符号

解决方法

  • 统一使用有符号类型(除非需要超大范围)。
  • 显式转换后比较:if (i < static_cast<int>(u))

字符串处理问题

C 风格字符串缓冲溢出
使用 char[]strcpy 时易发生缓冲区溢出:

char buf[10];
strcpy(buf, "12345678901"); // 溢出

解决方法

  • 使用 std::string 替代。
  • 必须用 C 风格字符串时,改用安全函数(如 strncpy)。

std::stringchar* 混淆
string.c_str() 返回的指针用于长期存储会导致悬垂指针:

const char* p = some_string.c_str();
some_string.modify(); // p 可能失效

解决方法

  • 立即使用 c_str() 返回的指针或复制其内容。
  • 优先使用 std::string_view(C++17 起)作为只读视图。

动态内存管理问题

内存泄漏
new 分配内存后未 delete

int* p = new int[100];
// 忘记 delete[] p;

解决方法

  • 使用智能指针(std::unique_ptr/std::shared_ptr)。
  • 优先选择容器类(如 std::vector)。

悬垂指针
释放内存后继续访问指针:

int* p = new int;
delete p;
*p = 42; // 未定义行为

解决方法

  • 释放后立即置空指针:delete p; p = nullptr;
  • 使用智能指针自动管理生命周期。

类型推导相关

auto 推导意外类型
auto 可能推导出非预期类型(如引用或常量):

const int x = 42;
auto y = x; // y 类型是 int 而非 const int
auto& z = x; // z 类型是 const int&

解决方法

  • 结合 decltype 或显式指定类型(如 auto const)。
  • 注意容器迭代器类型(如 std::vector<bool>::iterator 的特殊性)。

跨平台兼容性问题

数据类型大小不一致
intlong 等类型大小随平台变化(如 Windows 和 Linux 的 64 位差异)。
解决方法

  • 使用固定宽度类型(如 int32_tuint64_t)。
  • 通过 static_assert(sizeof(int) == 4) 检查类型大小。

字节序(Endianness)问题
不同平台对多字节数据的存储顺序可能不同(大端/小端)。
解决方法

  • 网络传输时统一转换为网络字节序(如 htonl/ntohl)。
  • 序列化数据时明确指定格式(如 Protocol Buffers)。

代码示例:安全类型转换模板

#include <type_traits>
#include <stdexcept>

template <typename To, typename From>
To safe_cast(From value) {
    static_assert(std::is_arithmetic_v<From>, "From must be numeric");
    static_assert(std::is_arithmetic_v<To>, "To must be numeric");

    if constexpr (std::is_signed_v<From> != std::is_signed_v<To>) {
        // 处理有符号/无符号转换
        if (value < 0 && !std::is_signed_v<To>) {
            throw std::overflow_error("Negative to unsigned conversion");
        }
    }
    return static_cast<To>(value);
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐