基本上我想做的是构建一个字符串类,如果传递一个静态字符串或指向一个的 constexpr 变量,它将简单地使用该指针,以后不会尝试删除它。
我认为我们在这里遇到了XY-problem。知道一个表达式是否是 constexpr 不会告诉你它是否适合 delete。
我想说,如果这个操作可能不合适,该函数不应该尝试猜测是否删除。我相信调用者应该处理好这个问题,可能使用智能指针来不处理这个问题。
换句话说,如果必须将指向的对象作为参数传递给函数,我会让函数接受左值引用,并让客户端取消对指针的引用。
我想说这种模式不仅仅在delete 的情况下有意义:更一般地说,如果一段代码具有决定如何生成或计算某些值的责任(例如对象分配),那么正确执行某些相关或相应操作(例如清理)的责任也应该属于同一段代码:
void foo(my_object& o)
{
// ...
}
my_object o;
foo(o);
// The argument has automatic storage, no need to delete
my_object* pO = new my_object();
foo(*pO);
// The argument was allocated through operator new, we must
// deallocate it through a corresponding call to delete
delete pO;
如果你真的希望清理在函数中进行,你应该给客户端一个方法来告诉函数如何执行它:
void foo(my_object& o, bool shouldDelete)
{
// ...
if (shouldDelete) { delete &o; }
}
my_object o;
foo(o, false); // "And don't try to deallocate this object please..."
my_object* pO = new my_object();
foo(*pO, true); // "Please, delete it for me" (we are delegating the
// responsibility of performing the material action,
// but not the one of knowing how!)
为了获得更大的灵活性,您甚至可以接受一个可调用对象,这通过“委派执行实质性操作的责任,而不是知道如何执行的责任,更清楚地说明了我在上述评论中的意思":
#include <functional>
void foo(my_object& o, std::function<void()> f = [] () { })
{
// ...
f();
}
int main()
{
my_object o;
foo(o); // "And don't do anything with this object when you're done..."
my_object* pO = new my_object();
foo(*pO, [=] () { delete pO; }); // "Please, do exactly this when done..."
}
如果您不需要在运行时确定可调用对象的类型,您甚至可以考虑将foo() 转换为函数模板。
最后,关于您最初关于如何确定表达式是否为常量表达式的问题,这通常是不可能的,但有一些技术可以在某些情况下帮助您 - 只需意识到他们的局限性。在这方面,您可能会发现this Q&A on StackOverflow 相关。