使用专用析构函数绕过模板错误

Bypass a template error with a private destructor

本文关键字:错误 专用 析构函数      更新时间:2023-10-16

在编译时,我遇到了以下问题,如何进行编译,因为从概念上讲,这是正确的,欢迎任何重构建议。

我得到了一个编译错误,因为"搜索"析构函数是私有的,但我不会在搜索指针上使用delete,因为我在初始化基类时提供了一个自定义Deleter。我知道编译器不知道如何绕过它。

错误描述:错误C2248:无法访问类"Search"中声明的私有成员编译器已在此处生成"搜索::~Search">

class Search
{
public:
static Search* New(/* */);    // using a pool of already allocated objects to avoid expensive allocations
static void Delete(Search*);
private:
Search(/* */) {/* */}
~Search() {/* */}
};

template<class T>
class MyList
{
public:
typedef (*CustomDeleter) (T* pElement);
MyList(CustomDeleter lpfnDeleter = NULL) {};

void Empty()
{
for (/**/)
{
if (m_pList[m_nListLastUsed])
{
if (m_lpfnCustomDeleter == NULL)
delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since
// I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it
else
m_lpfnCustomDeleter(m_pList[m_nListLastUsed]);
}
}
}
private:
T** m_pList;
CustomDeleter m_lpfnCustomDeleter;  // Pointer to a custom deleter
};
class Query : public MyList<Search>
{
public:
Query() : MyList<Search>(&Search::Delete) // I set a custom deleter since Search hides its destructor : is this the right way ?
{}
~Query()
{
/****/
Empty(); // PROBLEM HERE
/***/
}
};

确保'm_lpfnCustomDeleter'从不为NULL或更好的nullptr。如果用户没有提供任何自定义删除程序,则可以通过回退到默认的"删除程序"来确保这一点。

我想要下面这样的。

#include <iostream>
template <typename PointerType>
struct DefaultDeleter {
void operator()(PointerType* ptr) {
std::cout << "Deleten";
}
};
struct CustomDeleter {
void operator()(int* ptr) {
std::cout << "Custom int deleter" << std::endl;
}
};
template <typename T, typename Deleter = DefaultDeleter<T>>
class Whatever
{
public:
Whatever() {
std::cout << "Consn";
}
void deinit() {
Deleter d;
auto v = new T;
d(v); // Just for the sake of example
}
};
int main() {
Whatever<char> w;
w.deinit();
Whatever<int, CustomDeleter> w2;
w2.deinit();
return 0;
}

更新::不进行代码重构假设不进行c++11

  1. 把这个小的元程序添加到你的代码库中。

    命名空间my{

    template <typename T, typename U> struct is_same {
    static const bool value = false;
    };
    template <typename T>
    struct is_same<T, T> {
    static const bool value = true;
    };
    template <bool v, typename T = void> struct enable_if;
    template <typename T = void> struct<true, T> {
    typedef T type;
    };  
    }
    
  2. 将清空功能更改为:

    void Empty(){for(/****/){do_delete();}}

template<typename=typename my::enable_if<my::is_same<T、 搜索>::value>::type>void do_delete(){assert(m_lpfnCustomDeleter!=NULL);m_lpfnCustomDeleter(m_pList[m_nListLastUsed]);}无效do_delete(){删除m_pList[m_nListLastUsed];}

如果您使用的是c++11,则不必在命名空间"my"下编写元程序。只需将"my::is_same"answers"my::enable_if"替换为"std::is_ame"answers"std::enable_idf"。

注意:,尚未编译和测试上述代码。

将执行删除的代码与其他代码分开:

if (m_pList[m_nListLastUsed])
{
if (m_lpfnCustomDeleter == NULL)
delete m_pList[m_nListLastUsed]; // COMPILE ERROR HERE BECAUSE Search destructor is private BUT I won't use that instruction since
// I provided a custom Deletern I know that the compiler doesn't know that, how to bypass it
else
m_lpfnCustomDeleter(m_pList[m_nListLastUsed]);
}

将上面的代码替换为调用:

custom_delete(m_pList[m_nListLastUsed]);

然后将其添加为列表类的方法,不要忘记还包括<type_traits>

std::enabled_if<std::is_destructible<T>::value, void>::type custom_delete(T* ptr) {
/* Note: this isn't pre-2000 anymore, 'lpfn' as a prefix is horrible,
don't use prefixes! */
if (m_lpfnCustomDeleter) {
m_lpfnCustomDeleter(ptr);
} else {
delete ptr;
}
}
std::enabled_if<!std::is_destructible<T>::value, void>::type custom_delete(T* ptr) {
if (!m_lpfnCustomDeleter) {
throw "No custom deleter for a non destructible type!";
}
m_lpfnCustomDeleter(ptr);
}

如果对象具有私有析构函数,则enabled_if将使它可以直接delete对象的函数不存在于您的列表中。

或者,您可以传递一个充当自定义deleter的结构(或函数)作为列表的第二个模板参数,并将默认值作为调用delete运算符的参数,然后直接在指针上调用此结构,如Arunmu的anser中所示。