基本的に私がやりたいことは、静的文字列、またはそれを指す constexpr 変数を渡された場合、単にそのポインターを使用し、後で削除しようとしない文字列クラスを構築することです。
ここでXY 問題に直面していると思います。式が であるかどうかがわかっ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()
、関数テンプレートにすることを検討することもできます。
最後に、式が定数式であるかどうかを判断する方法に関する最初の質問に関して、これは一般的には不可能ですが、特定の状況で役立ついくつかの手法があります-それらの制限に注意してください。この点に関して、 StackOverflow に関するこの Q&A が関連していると思われるかもしれません。