C++ Debug:Invalid address specified to RtlValidateHeap

一世执手 提交于 2020-02-02 15:39:39

@Author:CSU张扬
@Email:csuzhangyang@gmail.com or csuzhangyang@qq.com
@我的网站: https://www.faker.top

Invalid address specified to RtlValidateHeap

1. 问题概述

报错如下:

HEAP[String.exe]: Invalid address specified to RtlValidateHeap( 02730000, 0274ED98 )

监视窗口各变量的值:
在这里插入图片描述

异常位置发生在 v.push_back(std::move(s2)); ,该语句进入了 free() 函数, 异常最后在函数 free() 的最后。free() 是我自定义的 String 类的析构函数内容,释放 allocator 分配的内存。


class String {
public:
    // 省略一部分代码。。。

    // 正确的代码
    String(String&& s) noexcept : sz(s.sz), p(s.p) {
        s.p = 0;
        s.sz = 0;
        std::cout << "move constructor" << std::endl;
    }
    // 错误的代码
    // String(String&& s) noexcept : sz(s.sz), p(s.p) {
    //     s.free();
    //     std::cout << "move constructor" << std::endl;
    // }
    String& operator=(String&&) noexcept;
    ~String() { free(); }
private:
    void free();
    static std::allocator<char> alloc;
    char *p;
    size_t sz;
};

void String::free() {
    if (p) {
        std::for_each(begin(), end(),
        [](const char& ptr) { alloc.destroy(&ptr); });
        // for (auto ptr = end(); ptr != begin();)
        //     alloc.destroy(--ptr);
        alloc.deallocate(p, sz);
    }
}

/* 主函数 */
int main() {
    String s1("one"), s2("two");
    String s3 = s1;
    s3 = s2;
    cout << "create an empty vector" << endl;
    vector<String> v;
    cout << "----v.reserve(5)----" << endl;
    v.reserve(5);
    cout << "----v.push_back(s1);----" << endl;
    v.push_back(s1);
    cout << "----v.push_back(std::move(s2));----" << endl;
    // 不会调用拷贝构造函数
    v.push_back(std::move(s2));  /* 异常位置 */
    cout << "----v.push_back(String(\"three\"));----" << endl;
    v.push_back(String("three"));
    cout << "----v.push_back(\"four\");----" << endl;
    // 调用const char*的构造函数生成一个临时量,再调用拷贝构造函数。
    v.push_back("four");
}

2. 解决思路

这其实是一段测试 移动构造函数 的代码,错误信息的字面意思就是 为RtlValidateHeap指定的地址无效

  1. 看监视窗口的变量值,p 字符串中的字符无效,初步认为是指针释放的错误。
  2. free() 函数最后一句 alloc.deallocate(p, sz) 正是释放内存,那么原因基本就确定下来了。
  3. std::move(s2) 会调用移动构造函数,那么可能是移动构造函数出现了问题。
  4. 之前写的错误的代码,我是想直接将右侧对象给释放掉。但是这么做是不对的,C++要求移后源必须处于可析构状态,那么我这么做就会导致它释放了两次,从而产生错误。

3. 解决办法

正确的做法是将右侧对象的指针置为 nullptr,其他内置类型置为初始值即可。

正确的输出结果如下:

const char*p constructor
const char*p constructor
copy constructor
copy assignment
create an empty vector
----v.reserve(5)----
----v.push_back(s1);----
copy constructor
----v.push_back(std::move(s2));----
move constructor
----v.push_back(String("three"));----
const char*p constructor
move constructor
----v.push_back("four");----
const char*p constructor
move constructor
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!