C++中xmalloc的右类似物
Right analogue of xmalloc in 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 memoryn";
abort();
}
return p;
}
int main()
{
int *p = xnew<int>(5000000000LL);
}
第二个问题,如果我从xnew<int>(5000000000LL);
调用中删除<int>
,编译器(g++ 4.7.2)无法再推断该[T = int]
,尽管返回类型int *
仍然存在。为什么?
编辑:使用new
版本时是否有任何开销,即使没有抛出也可能引发异常?我真的不想在非绝对必要时使用任何例外。
我不明白为什么这是必要的。new
会扔std::bad_alloc
如果它无法分配内存。如果不处理异常,则此 将导致对std::terminate
的调用,从而有效地结束 程序,并且具有与xmalloc
相同的行为。
当然,当您的编译器不实现异常时,这种情况会发生变化。
第二个问题,
<int>
如果我从xnew<int>(5000000000LL);
调用中,编译器 (g++ 4.7.2) 无法推断 [T = int] 了,尽管返回类型 int * 仍然存在。为什么 那是?
函数模板参数仅从函数调用中的参数表达式类型推导。由于T
不会以任何方式出现在函数参数中,因此无法推断。
您对函数调用的返回值执行的操作不会影响C++中的模板参数推导。如果你写int *p = some_function(5000000000LL);
那么int*
不一定是some_function
的返回类型,它是编译器将尝试将返回类型转换为some_function
的类型。
因此,编译器无法推断出int
的近端原因是标准禁止它(至少,没有诊断)。最终的原因是C++的设计者(可能是Stroustrup最初)想要限制考虑的事情。 对于演绎,保持规则,如果不是简单的,那么至少是凡人可以理解的。
C++有一条规则,即子表达式的类型仅取决于子表达式本身,而不取决于周围的表达式。AFAIK 只有一个例外,即函数指针或成员函数指针不明确时:
void foo();
void foo(int);
void (*pfoo1)() = &foo; // &foo evaluates to a pointer to the void overload
void (*pfoo2)(int) = &foo; // &foo evaluates to a pointer to the int overload
void (*pfoo3)() = (void(*)(int))&foo; // &foo evaluates to the int overload, but doesn't convert to the type of pfoo3 so the line fails.
此代码不能保证 100% 安全,因为operator<<()
可能会抛出。实际上,这种情况并不普遍,因为投掷应该满足一些罕见的条件:
std::cerr
在其exceptions()
掩码中设置了badbit
(默认情况下不是)- 输出期间引发异常
在这种情况下,将重新引发异常,内存将泄漏。
关于从模板函数调用表达式中删除<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
异常开销实际上取决于实现。我相信现代编译器足够聪明,如果可能的话,可以避免这种开销,但你应该用你的平台检查一下,以确保。
如果你想避免异常抛出new
(无论出于何种原因 - 也许你正在一个不支持异常的平台,比如一些嵌入式平台),你可以提供一个new_handler
,以便在new
无法分配内存时中止程序:
#include <stdlib.h>
#include <iostream>
#include <new>
namespace {
void new_handler_abort()
{
std::cerr << "Not enough memoryn";
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()
之前遇到内存问题,它可能无法完全按照您的要求执行。
编译器 - 可能仍会添加代码以支持异常处理,并且对于某些编译器,它包含每次调用
operator new
时发生的代码,因此可能仍会花费少量开销来处理永远不会发生的异常(较新的编译器可以通过使用表驱动的堆栈展开来避免此开销,从而避免在每次调用时运行代码来设置异常)。
- 如何在c++中使用引用实现类似python的行为
- 使用Qt C++计算类似Git的SHA1哈希
- Visual Studio 中是否有来自代码块的编译器标志的类似物?
- C++合并类似物
- C# 通用比较方法 [C++模板的类似物]
- STD ::与指定线程的异步类似物
- QT有GSL :: Span的类似物吗?
- 用于嵌入式设备的轻巧SMBClient类似物
- C#扩展方法类似物在C 中
- Python方法的OpenCV C 类似物
- Pascal类型二进制文件的C++和Python类似物
- 整数输出格式.什么是 printf(%.3x) 的类似物
- C++中xmalloc的右类似物
- 除了函数之外,是否有对象的"this"的类似物?
- 不带GLkit的OpenGL ES.GLKMatrix和纯OpenGL ES中函数的类似物
- 与 Ruby's Rack 最接近C++类似物是什么?
- _mm_cvtsd_f64高阶浮点的类似物
- Altivec:_mm_sad_epu8()的类似物
- DirectX — 有没有类似 DirectDraw surface Flip() 的类似物
- c++中的strtok()类似物