C ++中xmalloc的正确类比

时间:2012-11-22 09:36:16

标签: c++

两个简单的问题:在普通C中,我们经常使用xmalloc这是一个分配或中止例程。我用C ++实现了它。这是一个正确的无异常实现吗?

template <typename T>
T *xnew(const size_t n)
{
    T *p = new (std::nothrow) T[n];
    if (p == nullptr)
    {
        cerr << "Not enough memory\n";
        abort();
    }
    return p;
}

int main()
{
    int *p = xnew<int>(5000000000LL);
}

第二个问题,如果我从<int>调用中删除xnew<int>(5000000000LL);,编译器(g ++ 4.7.2)就不能再推断那个[T = int]了,尽管返回类型int *仍然存在。那是为什么?

编辑:使用new版本时,是否有任何开销,即使它没有被抛出也会引发异常?在非绝对必要时,我真的不想使用任何例外。

4 个答案:

答案 0 :(得分:5)

我不明白为什么这是必要的。 new会抛出std::bad_alloc 如果它没有分配内存。如果你不处理异常,这个 将导致致电std::terminate,这有效地结束了 程序,与xmalloc具有相同的行为。

当然,当编译器没有实现异常时,这会发生变化。

答案 1 :(得分:3)

  

第二个问题,如果我从中移除<int>   xnew<int>(5000000000LL);调用,编译器(g ++ 4.7.2)无法推断   虽然返回类型int *仍然存在,但[T = int]已经存在。为什么   那是吗?

函数模板参数仅从函数调用中的参数表达式的类型推导出来。由于T没有以任何方式出现在函数参数中,因此无法推断出它。

使用函数调用的返回值所做的事情不会影响C ++中的模板参数推导。如果您编写int *p = some_function(5000000000LL);,那么int* 不一定是返回类型some_function,它是编译器将尝试转换{的返回类型的类型{1}}。

因此,编译器无法推导some_function的近因是标准禁止它(至少没有诊断)。最终的原因是C ++的设计者(最初可能是Stroustrup)想要限制所考虑的事情 对于扣除,保持规则,如果不简单,那么至少可以理解为凡人的头脑。

C ++中有一条规则,即子表达式的类型仅取决于子表达式本身,而不取决于周围的表达式。而AFAIK只有一个例外,即函数指针或成员函数指针不明确时:

int

答案 2 :(得分:1)

此代码不保证100%安全,因为operator<<() 可能会抛出。实际上它并不普遍,因为扔掉那里会遇到一些罕见的情况:

  1. std::cerr在其badbit掩码中设置exceptions()(默认情况下不是)
  2. 输出期间抛出异常
  3. 在这种情况下,异常将被重新抛出并且内存将泄漏。

    关于从模板函数调用表达式中删除<int> - 当然它不起作用。编译器只能从调用表达式本身推导出模板参数类型,而不是从它将被赋值的左值类型推导出。因此,您希望自动推导出的模板参数应该是函数参数,而不是返回类型:

    template <class T> T f1();
    template <class T> T f2(T);
    
    int a = f1();   // Will not compile, shall be f1<int>();
    int b = f2(42); // OK
    

    异常开销实际上取决于实现。我相信现代编译器足够聪明,如果可能的话可以避免这种开销,但是你应该用你的平台来检查它。

答案 3 :(得分:1)

如果你想避免抛出new的异常(无论出于何种原因 - 也许你正在一个不支持例外的平台上工作,比如某些嵌入式平台),你可以提供{{1}如果new_handler无法分配内存,则中止程序:

new

仅仅将此源文件作为程序的一部分包含将安装#include <stdlib.h> #include <iostream> #include <new> namespace { void new_handler_abort() { std::cerr << "Not enough memory\n"; abort(); } struct new_handler_abort_installer { new_handler_abort_installer() { std::set_new_handler(new_handler_abort); } }; // a statically allocated object that does nothing but install the // new_handler_abort() function as the new_handler new_handler_abort_installer install_new_handler_abort; } 将导致程序中止,new_handler无法分配内存。

然而:

  • 这个初始化完成时不确定(除了它会在new被调用之前发生)。因此,如果您在main()之前遇到内存问题,则可能无法完全按照您的意愿执行。
  • 编译器可能仍然添加代码以支持异常处理,并且对于某些编译器包含每次调用main()时发生的代码,因此可能仍会有一些少量的开销处理永远不会发生的异常(较新的编译器可以通过使用表驱动的堆栈展开来避免这种开销,避免必须运行代码来在每次调用时设置异常)。