通过删除析构函数实现非不稳定类



我有一个纯粹用于语法目的的class,以某种方式调用函数。这是一个简化的示例:

#include<iostream>
template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};
int main(){
    double d = make<double>::from(2);
    std::cout << d << 'n';
}

现在,假设我想警告用户这个类不应该被实例化。类可能是不稳定的,但是我很好奇是否有可能禁止这种行为?

首先我尝试删除默认构造函数

template<class T1>
struct make{
    make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

但这仍然是可能的:

make<double> m{}; // valid

最后,我尝试删除析构函数,这似乎工作

template<class T1>
struct make{
    ~make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

但似乎仍然可以由new分配类。

我应该同时删除析构函数和删除构造函数吗?(复制和移动构造函数呢?)

这是禁止实例化的最好方法吗?这里的代码:http://coliru.stacked-crooked.com/a/0299c377c129fffb

#include<iostream>
template<class T1>
struct make{
    make() = delete;
    ~make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};
int main(){
    double d = make<double>::from(2);
    std::cout << d << 'n';
    make<double> m{}; // compile error (no destructor)
    auto p = new make<double>{}; // compile error (no constructor)
}

但这仍然是可能的:

make<double> m{}; // valid

…我不知道这能行。但是现在我知道了,我也知道了为什么有效。因此,如何阻止它。

它可以工作,因为你声明的make<T>是一个集合。即使它有一个删除的默认构造函数,c++仍然认为它是一个聚合。如果你在聚合上使用大括号初始化列表,你会得到聚合初始化。

停止它的方法很简单:使它不再是聚合:

template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
    make() = delete;
private:
    char c; //Not an aggregate
};

私有成员强制make<T>不再是聚合。因此,它不能用于聚合初始化,因此{}将尝试调用默认构造函数。这自然会失败,因为它被删除了。

仍然可以使用简单的可复制操作来创建make<T>实例。你可以通过给它一个virtual析构函数来关闭它们:

template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
    make() = delete;
private:
    char c; //Not an aggregate
    virtual ~make() = default;
};

这应该足以防止合法的c++代码创建该类型的对象。

最新更新