C++ 运算符重载错误检查无异常

标签 c++ embedded operator-overloading safety-critical

我有一个类似于 vector 的类,它主要是一个动态大小的数组。我正在为资源有限的平台编写它,因此我必须不使用异常。

很明显,要使用运算符重载来简化此类动态分配的接口(interface),必须在某些运算符重载函数中执行。赋值运算符 (=) 就是一个例子。

尽管无一异常(exception),以一种明智的方式将错误的分配错误通知调用者,同时仍然保持强大的错误安全性变得相当具有挑战性。我可以有一个类的错误属性,调用者必须在每次涉及动态分配的调用后检查它,但这似乎不是一个最佳解决方案。

编辑:

这是我目前得到的最好的想法(在上一段中被突出显示为一个不太理想的解决方案),任何改进将不胜感激:

dyn_arr & dyn_arr::operator=(dyn_arr const & rhs) {
    if (reallocate(rhs.length)) // this does not destroy data on bad alloc
       error |= bad_alloc; // set flag indicating the allocate has failed
    else {
        size_t i;
        for (i = 0; i < rhs.length; ++i) // coppy the array
            arr[i] = rhs.arr[i]; // assume this wont throw an exceptions and it wont fail
    }
    return *this;
}

然后调用:

dyn_arr a = b;
if (a.error)
  // handle it...

我还没有编译这个,所以可能会有拼写错误,但希望你明白了。

最佳答案

这里有两个不同的问题。

第一个与运算符重载有关。正如 CashCow 所提到的,C++ 中的重载运算符只是函数调用的语法糖。特别是,运算符不需要 return *this .这只是一种编程约定,旨在促进运算符链接。

现在,链接赋值 运算符 ( a = b = c = ... ) 是 C++ 应用程序中的一个极端情况。因此,明确禁止 dyn_arr 的用户可能会更好。永远链赋值运算符的类。这将使您可以自由地从运算符返回错误代码,就像从常规函数中一样:

error_t operator = (dyn_arr const & rhs) {
    void *mem = realloc(...);
    if (mem == NULL) {
        return ERR_BAD_ALLOC; // memory allocation failed
    }
    ...
    return ERR_SUCCESS; // all ok
}

然后在调用者代码中:

dyn_arr a, b;
if ((a = b) != ERR_SUCCESS) {
    // handle error
}

第二个问题与您给出的实际示例有关:

dyn_arr a = b;

这个例子将调用重载的赋值运算符!相反,它意味着“构造 dyn_arr 对象 a 并将 b 作为构造函数的参数”。所以这一行实际上调用了dyn_arr的拷贝构造函数.如果您有兴趣了解原因,请从效率的角度考虑。如果该行的语义包括调用赋值运算符,运行时系统将作为该行的结果做两件事:构造a。具有一些默认状态,然后通过分配给 a 立即销毁该状态b的状态| .相反,只做一件事——调用复制构造——就足够了。 (并导致相同的语义,假设复制构造函数和赋值运算符的任何合理实现。)

不幸的是,您认识到这个问题很难处理是正确的。除了抛出异常之外,似乎没有真正优雅的方法来处理构造函数中的失败。如果你不能这样做,要么:

  • 在构造函数中设置一个标志并要求/建议用户事后检查它,或者
  • 要求指向已分配内存区域的指针是 作为参数传递给构造函数。

有关详细信息,请参阅 How to handle failure in constructor in C++?

关于C++ 运算符重载错误检查无异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25444357/

相关文章:

c++ - 如何在linux中指定套接字使用哪个接口(interface)

具有隐式参数的 C++ 函数模板实例化

c++ - 在 operator+= 中使用 operator+ 比不使用它慢吗?

c++ - 模板类运算符重载多个类型名 C++

c++ - 重载赋值运算符 - 多态容器

c++ - 如何为应用程序中的某些按钮重置 QApplication::styleSheet?

c++ - glRotatef 移动轴

c - newlib-nano printf 在嵌入式项目中转换为 iprintf

sqlite - 嵌入式文件系统和sqlite

c - 如何使用简单的转义序列对东欧(波兰)符号进行编码?