在编译时,我遇到了以下问题,如何进行编译,因为从概念上讲,这是正确的,任何重构建议都是受欢迎的。
我收到了编译错误,因为"搜索"析构函数是私有的,但我不会在搜索指针上使用delete,因为我在基类的初始化中提供了自定义Deleter。我知道编译器不知道如何绕过它。
错误说明: 错误C2248:无法访问在课程中声明的私人成员'搜索' 编译器已生成'搜索::〜搜索'这里
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
/***/
}
};
答案 0 :(得分:3)
确保&#39; m_lpfnCustomDeleter&#39;永远不是NULL或更好的nullptr。你可以通过回到默认的“删除者”来确保这一点。如果用户没有提供任何自定义删除器。
我更喜欢下面的内容。
#include <iostream>
template <typename PointerType>
struct DefaultDeleter {
void operator()(PointerType* ptr) {
std::cout << "Delete\n";
}
};
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 << "Cons\n";
}
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
将这个小的元程序添加到您的代码库中。
命名空间{{/ p>
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;
};
}
将空功能更改为:
void Empty(){
for(/ **** /){
do_delete();
}
}
template <typename = typename my::enable_if<my::is_same<T, Search>::value>::type> void do_delete() { assert (m_lpfnCustomDeleter != NULL); m_lpfnCustomDeleter(m_pList[m_nListLastUsed]); } void do_delete() { delete m_pList[m_nListLastUsed]; }
如果您使用的是c ++ 11,那么您就不必在命名空间&#39; my&#39;下编写元节目。只需替换我的:: is_same&#39;和我的:: enable_if&#39;与&#39; std :: is_same&#39;和&#39; std :: enable_if&#39;。
注意:,尚未编译和测试上述代码。
答案 1 :(得分:1)
将执行删除的代码与其余代码分开:
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
直接存在的函数。
或者,您可以将充当自定义删除器的结构(或函数)作为列表的第二个模板参数传递,默认值为调用delete运算符的值,然后直接在指针上调用此结构,如Arunmu的anser。