具有重载类型转换运算符的函数对象崩溃

function object with overloaded type conversion operator crashes

我正在实现类型擦除class(我正在研究模板和静态多态性),它可以包装任何可调用对象(任何支持函数调用语法的对象)。

阅读 C++ 模板完整指南并在网上搜索,我想出了这个实现:

// erasure.hpp 

class Object
{
friend void swap(Object &, Object&);  // friend declaration
private:
    class Concept
    {
    public:
        virtual ~Concept() = default;
        virtual void Invoke() = 0;
        virtual Concept *Clone() = 0;
    protected:
        Concept() = default;
    };
    template <typename T>
    class Model : public Concept
    {
    public:
        //Model(const T&) : mObject(object) {}
        //Model(T&&) : mObject(move(object)) {}
        template <typename U>                          // forwarding constructor (forwarding (universal) reference)
        Model(U &&object) : mObject(forward<U>(object)) {}    
        void Invoke() override { mObject(); }
        Model *Clone() override;
    private:
        T mObject;
    };
public:
    template <typename T>                              // forwarding constructor (forwarding (universal) reference)
    Object(T &&object) : mConcept(new Model<typename remove_reference<T>::type>(forward<T>(object))) {}  
    Object(const Object &other) : mConcept(other.mConcept->Clone()) {}               // copy constructor
    Object(Object &other) : Object(static_cast<const Object&>(other)) {}             // delegating constructor (inhibits forwarding constructor)
    Object(Object &&other) : mConcept(other.mConcept) { other.mConcept = nullptr; }  // move constructor
    ~Object() {delete mConcept; }                 // destructor
    template <typename T>                         // forwarding assignment operator
    Object &operator=(T&&);
    Object &operator=(const Object&);             // copy assignment operator
    Object &operator=(Object &other) { return *this = static_cast<const Object&>(other); }
    //Object &operator=(Object &other) { return this->operator=(static_cast<const Object&>(other)); }
    Object &operator=(Object&&);                  // move assignment operator
    void operator()();
private:
    Concept *mConcept;
};

template <typename T>
Object::Model<T> *Object::Model<T>::Clone()
{
    return new Model(mObject);
}

template <typename T>
Object &Object::operator=(T &&object)
{
    delete mConcept;  
    mConcept = new Model<remove_reference_t<T>>(forward<T>(object));

    return *this;
}

这非常class简洁明了,所以我省略了 cpp 实现文件。当我从自由函数、重载函数调用运算符的仿函数甚至 lambda 构造类型擦除对象时,它工作正常:

#include "erasure.hpp"
#include <iostream>

#define PRINT(msg)       std::cout << (msg)
#define PRINTLN(msg)     PRINT(msg) << std::endl;

void FreeFunction()
{
    PRINTLN("in free function");
}

class Functor1
{
public:
    void operator()()
    {
        PRINTLN("in functor overloaded function call operator");
    }
};

class Functor2
{
private:
    typedef void(*PtrToFun)();
public:
    operator PtrToFun()
    {
        PRINTLN("in functor overloaded type conversion operator to function pointer");
    }
};

int main(int argc, char **argv)
{
    Object o1 = &FreeFunction;
    Object o2 = Functor1();
    Object o3 = Functor2();
    Object o4 = []() -> void { PRINTLN("in lambda"); };

    o1();
    o2();
    o4();
    o3();  // error: program crashes

    return 0;
}

但是当我使用将类型转换运算符重载为函数指针的仿函数 (Functor2) 时,程序在运算符中打印字符串后崩溃。它只是冻结和崩溃(堆栈溢出?)。

为什么?

编辑

在 rafix07 发表评论后,我编辑了代码,现在可以使用了:

class Functor2
{
private:
    typedef void(*PtrToFun)();
    PtrToFun p = []() { PRINTLN("in functor overloaded type conversion operator to function pointer"); };
public:
    operator PtrToFun()
    {
        return p;
    }
};

您的 Functor2 只是函数指针的包装器,因此它应该在转换运算符中使用一些指针并 return 它。没有 return,你有 UB 因为在垃圾地址上调用函数。

要使 Functor2 接受任何带有签名 void () 的函数,您可以这样写:

class Functor2
{
private:
    typedef void(*PtrToFun)();
    PtrToFun ptr;
public:
    Functor2(PtrToFun p ) : ptr(p) {}

    operator PtrToFun()
    {
        PRINTLN("in functor overloaded type conversion operator to function pointer");
        return ptr;
    }
};

Object o3 = Functor2(&FreeFunction);
o3();