今日、生ポインタをstd::unique_ptr
に変更するために一部のコードをリファクタリングしていたのに、order of evaluationのバグが原因でセグメンテーションフォルトが発生しました。C++ 17の式の評価順序とstd :: move
古いコードは、次のような何かをした:
void add(const std::string& name, Foo* f)
{
_foo_map[name] = f;
}
void process(Foo* f)
{
add(f->name, f);
}
std::unique_ptr
を使用するコードの最初の、素朴な、リファクタリング:
void add(const std::string& name, std::unique_ptr<Foo> f)
{
_foo_map[name] = std::move(f);
}
void process(std::unique_ptr<Foo> f)
{
add(f->name, std::move(f)); // segmentation-fault on f->name
}
ので、リファクタリング、コードは、セグメンテーションフォールトが発生します2番目の引数(std::move(f)
)が最初に処理され、1番目の引数(f->name
)が移動された変数boomを参照解除します。
これに対する可能な修正がadd
への呼び出しでそれを移動する前Foo::name
のハンドルを取得するために、次のとおりです。
void process(std::unique_ptr<Foo> f)
{
const std::string& name = f->name;
add(name, std::move(f));
}
それとも:
void process(std::unique_ptr<Foo> f)
{
Foo* fp = f.get();
add(fp->name, std::move(f));
}
これらのソリューションの両方が余分な行が必要ですadd
への(UBであっても)元のコードとほぼ同じようには見えません。
質問:
が慣用 C++上記2つの提案されたソリューションのどちらかである、とされていない場合、より良い代替手段がありますか?
P0145R3 - Refining Expression Evaluation Order for Idiomatic C++のためにC++ 17に変更があります。これにより、上記の解決策のいずれかが変わるか、落とし穴が防止されますか?
私は、 'add'関数をリファクタリングするか、' std :: unique_ptr 'オブジェクトを取るオーバーロードを追加するという"慣用的 "な解決策を言います。 –
@Someprogrammerdudeちょうど、 'process'から' add'に名前のハンドルを取得するという要件を変更するでしょうか?またはP0145R3はこの問題に対処していますか? –
IMOできるだけスタックの遠くまでこれらの詳細をプッシュするのが一般的には良い考えです。結局のところ、抽象化はOOとC++の主要な部分の1つです。 –