虚函数读取访问冲突
Read Access Violation on Virtual Function
这是我的程序的简化版本。
#include <iostream>
#include <vector>
class Base
{
public:
Base()
{
}
void virtual update()
{
std::cout << "no update function\n";
}
void virtual draw()
{
std::cout << "no draw function\n";
}
};
class Derived : public Base
{
public:
Derived();
void draw() override;
void update() override;
};
Derived::Derived()
{
}
void Derived::draw()
{
std::cout << "draw";
}
void Derived::update()
{
std::cout << "update";
}
class Caller
{
public:
Caller();
void update();
void draw();
void reg_obj(Base* obj);
private:
std::vector<std::shared_ptr<Base>> all_objects;
};
Caller::Caller()
{
Derived derived_class{};
reg_obj(&derived_class);
}
void Caller::update()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->update();
}
}
void Caller::draw()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->draw();
}
}
void Caller::reg_obj(Base* obj)
{
all_objects.push_back(std::shared_ptr<Base>{obj});
}
int main()
{
Caller caller{};
while (true)
{
caller.update();
caller.draw();
}
}
此代码有效,但当它在我的完整程序中 caller.update();
和 caller.draw();
之间时,内存中的 __vfptr 值不会保持不变。当接近 caller.draw()
时,__vfptr 值在调试器的每一步都会发生变化。我不确定如何诊断 __vfptr 中的内存损坏,因为它不是我编写的,而是 C++ 标准的一部分。任何帮助表示赞赏。不,我无法制作可复制的版本。我不知道为什么。我确实努力让它可以重现。
https://youtu.be/yd-76qDa7xc <- 这个视频显示了问题
https://github.com/Sage-King/Alienor <- 非功能代码的来源
Remy Lebeau 的解决方案:
Derived derived_class{}; reg_obj(&derived_class);
导致您的其余代码出现未定义的行为。您正在存储一个指向本地对象的指针,该对象随后被销毁,在 all_objects
向量中留下一个悬空指针。您对 all_objects
元素的所有方法调用都作用于无效内存。要解决这个问题,请更改 void reg_obj()
以采用 shared_ptr<Base>
并将其按原样存储,然后更改 Caller()
以使用 std::make_shared()
创建 Derived
对象,就像这样: void Caller::reg_obj(std::shared_ptr<Base> obj) { all_objects.push_back(obj); } Caller::Caller() { reg_obj(std::make_shared<Derived>()); }
这是我的程序的简化版本。
#include <iostream>
#include <vector>
class Base
{
public:
Base()
{
}
void virtual update()
{
std::cout << "no update function\n";
}
void virtual draw()
{
std::cout << "no draw function\n";
}
};
class Derived : public Base
{
public:
Derived();
void draw() override;
void update() override;
};
Derived::Derived()
{
}
void Derived::draw()
{
std::cout << "draw";
}
void Derived::update()
{
std::cout << "update";
}
class Caller
{
public:
Caller();
void update();
void draw();
void reg_obj(Base* obj);
private:
std::vector<std::shared_ptr<Base>> all_objects;
};
Caller::Caller()
{
Derived derived_class{};
reg_obj(&derived_class);
}
void Caller::update()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->update();
}
}
void Caller::draw()
{
for (int i = 0; i < all_objects.size(); i++)
{
all_objects[i]->draw();
}
}
void Caller::reg_obj(Base* obj)
{
all_objects.push_back(std::shared_ptr<Base>{obj});
}
int main()
{
Caller caller{};
while (true)
{
caller.update();
caller.draw();
}
}
此代码有效,但当它在我的完整程序中 caller.update();
和 caller.draw();
之间时,内存中的 __vfptr 值不会保持不变。当接近 caller.draw()
时,__vfptr 值在调试器的每一步都会发生变化。我不确定如何诊断 __vfptr 中的内存损坏,因为它不是我编写的,而是 C++ 标准的一部分。任何帮助表示赞赏。不,我无法制作可复制的版本。我不知道为什么。我确实努力让它可以重现。
https://youtu.be/yd-76qDa7xc <- 这个视频显示了问题 https://github.com/Sage-King/Alienor <- 非功能代码的来源
Remy Lebeau 的解决方案:
Derived derived_class{}; reg_obj(&derived_class);
导致您的其余代码出现未定义的行为。您正在存储一个指向本地对象的指针,该对象随后被销毁,在 all_objects
向量中留下一个悬空指针。您对 all_objects
元素的所有方法调用都作用于无效内存。要解决这个问题,请更改 void reg_obj()
以采用 shared_ptr<Base>
并将其按原样存储,然后更改 Caller()
以使用 std::make_shared()
创建 Derived
对象,就像这样: void Caller::reg_obj(std::shared_ptr<Base> obj) { all_objects.push_back(obj); } Caller::Caller() { reg_obj(std::make_shared<Derived>()); }