我的问题来自于我的一个c ++练习(来自C ++中的Programming Abstraction,2012版,练习12.2)。这是:
void strcpy(char *dst, char *src) { while (*dst++ = *src++); }
strcpy的定义很危险。危险源于这一事实 strcpy没能检查到有足够的空间 接收副本的字符数组,从而增加了机会 缓冲区溢出错误。但是,有可能消除很多 通过使用动态分配为其创建内存空间的危险 复制的字符串。写一个函数
char *copyCString(char *str);
为C风格的字符串str分配足够的内存然后 复制字符 - 以及终止空字符 - 进入 新分配的记忆。
这是我的问题:
这种新方法真的安全吗?为什么它安全?
我的意思是,有点激进,如果堆中没有足够的空间怎么办?
如果没有足够的空间,new
操作员是否能够检查空间可用性并以优雅的方式下降?
这会导致其他类型的“溢出”吗?
答案 0 :(得分:2)
如果new
无法分配请求的内存,则应该抛出std::bad_alloc
异常(但请参阅下文了解更多信息)。在那之后,堆栈将被展开到匹配的异常处理程序,并且它将由您的代码决定从那里开始做什么。
如果你真的想要/需要确保抛出异常,你可以使用nothrow
new
版本的std::string
将返回指向信号失败的空指针 - 但这包括几乎完全用于C兼容性,并且不经常使用(或有用)。
对于问题中引用的情况类型,您通常希望使用new
而不是自己搞乱分配空间。
另请注意,在许多现代系统中,{{1}} 的概念在发生故障时抛出或返回空指针,这实际上是相当陌生的。实际上,Windows通常会尝试扩展页面文件以满足您的请求。 Linux有一个" OOMKiller"试图找到"坏"处理并杀死它们以便在用完时释放内存。
因此,即使C ++标准(和C标准)规定了如果分配失败会发生应该的情况,那么现实生活中很少会发生这种情况。
答案 1 :(得分:1)
如果不能分配内存,则new运算符将抛出bad_alloc异常,除非指定了nothrow。如果指定constant nothrow,如果无法分配内存,则会返回NULL指针。
答案 2 :(得分:0)
strcpy的代码是不安全的,因为它会尝试在 dst 指针的已分配内存之外进行复制。例如:
int main()
{
const char* s1 = "hello"; // allocated space for 6 characters
char* s2 = new char[ 2 ]; // allocated space for 2 characters.
strcpy( s2, s1 );
cout << s2 << endl;
char c; cin >> c;
return 0;
}
这会打印正确的值&#34; hello&#34;但请记住,指针 s2 仅分配给2个字符的空格。所以我们可以假设其他字符被写入后续的内存插槽,这是不安全的,因为我们可能会覆盖数据或访问无效的内存。
考虑这个解决方案:
char* e4_strdup( const char*& c )
{
// holds the number of space required for the c-string
unsigned int sz{ 0 };
// since c-style strings are terminated by the '\0' character,
// increase the required space until we've found a '\0' character.
for ( const char* p_to_c = c; *p_to_c != '\0'; ++p_to_c )
++sz;
// allocate correct amount of space for copy.
// we do ++sz during allocation because we must provide enough space for the '\0' character.
char* c_copy{ new char[ ++sz ] }; // extra space for '\0' character.
for ( unsigned int i{ 0 }; i < sz; ++i )
c_copy[ i ] = c[ i ]; // copy every character onto allocated memory
return c_copy;
}
如果内存不足, new 运算符仍将返回std :: bad_alloc异常。