我正在尝试使用一些函数指针和模板进行类型擦除,如下面的示例所示。我发现奇怪的是,与GCC相比,我得到了错误的结果,与VS 2017一样,我得到了预期的结果。那么,谁是正确的,谁是错误的,为什么呢?
COLIRU上的实时示例:http://coliru.stacked-crooked.com/a/225db5711c07c8b0
struct A { void PrintA() { std::cout << "Event A" << std::endl; } };
struct B { void PrintB() { std::cout << "Event B" << std::endl; } };
struct C { void PrintC() { std::cout << "Event C" << std::endl; } };
struct RunBase
{
virtual void operator()() = 0;
};
template <typename T>
struct Run : public RunBase
{
using FUNC = void (T::*)();
Run(T& o, FUNC&& f) : mObj(o), mFunc(f) {}
void operator()() override { (mObj.*mFunc)(); }
T& mObj;
FUNC& mFunc;
};
int main()
{
A a;
B b;
C c;
std::vector<std::unique_ptr<RunBase> > mFuncs;
mFuncs.push_back(std::make_unique<Run<A> >(a, &A::PrintA));
mFuncs.push_back(std::make_unique<Run<B> >(b, &B::PrintB));
mFuncs.push_back(std::make_unique<Run<C> >(c, &C::PrintC));
for (auto& i : mFuncs)
(*i)();
return 0;
}
预期结果:
Event A
Event B
Event C
但GCC给了我
Event C
Event C
Event C
答案 0 :(得分:3)
这是因为您将引用存储在对象内部,但是&A::PrintA
等是临时变量,它们在完整表达式的末尾被销毁,因此成员引用处于悬空状态,使用它会导致未定义的行为
只需存储成员函数指针的副本即可对其进行修复:
FUNC mFunc;
PS。当mFuncs
被销毁时,唯一指针通过基本指针删除子对象。除非您声明RunBase::~RunBase
为虚拟,否则行为是不确定的。
那么,谁是正确的,谁是错误的,为什么?
您的程序有误;没有正确的行为。