c ++:用于动态分配的新运算符是否检查内存安全性?

时间:2015-03-25 00:11:49

标签: c++ dynamic heap allocation

我的问题来自于我的一个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操作员是否能够检查空间可用性并以优雅的方式下降? 这会导致其他类型的“溢出”吗?

3 个答案:

答案 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异常。