0

関数から非ポインタを返すためのベストプラクティスは何ですか?constそのポインタは(非const)ポインタを変更することによって取得されましたconstか?このような:

NODE *top_level(const NODE *input)
{
  while (input->parent != nullptr)
    input = input->parent;  // NODE::parent is (non-const) NODE*

  return input;  // Compile failure: 
                 // Cannot convert from 'const NODE *' to 'NODE *'
}

私は帰りに離れることができconst_castましconstた、それは問題ないようですが、より良い方法はありますか?

4

3 に答える 3

6

少なくとも標準ライブラリでのベストプラクティスはconstconstオーバーロードを提供しないことです。たとえば、としてstd::strchr宣言されています<cstring>

char *strchr(char *s, int c);
char const *strchr(char const *s, int c);

同様に、次のような機能にstd::map<T>::findは過負荷があります

iterator find(const Key& key);
const_iterator find(const Key& key) const;

const最初のバージョンには修飾子がないことに注意してください。findそれ自体には変更する理由がありませんmap。(*)ポイントは、マップの変更に使用できるfindものを取得することです。つまり、一種の「推移性推移性」、することはできません。同じ状況があなたの問題にも当てはまると思います。findconst

または、を使用することもできますがconst_cast、私にとっては、それは約束を破ったような気がします。

この状況の面白い点は、ツリーの最上位のアイテム(または入力が何であれ)で関数が呼び出されないことを保証できる場合は、キャストやオーバーロードの必要がないことです。

struct node {
    node *parent;
};

node *top(node const *n)
{
    node *p = n->parent;
    while (p->parent != 0)
        p = p->parent;
    return p;
}

警告なしでコンパイルします。

(*)std::mapスプレー木として実装された場合find、それを変更する必要がありますが、複雑さが保証されているため、標準ではスプレー木は許可されていないと思います。

于 2013-02-06T11:55:56.310 に答える
2

[編集:両方の編集の後、私の答えとlarsmansは同じになりましたが、順序が異なり、オプションごとに詳細レベルが異なります。ラースマンとの間に重要な違いが見られない限り、この回答にわざわざ賛成しないことをお勧めします。誰も見つからない場合は削除します。]

const-nessが*input、関数がリストのさらに上にある他のノードを変更する手段を提供しないことを意味しないことが確実な場合、修正は次のようになります。

NODE *top_level(const NODE *input_)
{
  NODE *input = const_cast<NODE*>(input_);
  while (input->parent != nullptr)
    input = input->parent;

  return input;
}

しかし、関数はで渡されたものとまったく同じポインタ値を返すことができるため、これは私には間違っているように思われます。

したがって、他のコード(呼び出し元ではありますが)に入力を変更する手段を与えることができるため、その入力をとしてマークしないでくださいconststrstr「正しい」解決策は、constおよびnon-constオーバーロードを提供することです。これにより、オーバーロードされていないCバージョンや、non-constを返す他の文字列検索関数など、「constnessを密輸する」関数の記述を回避できます。

同じノードへのポインターからconstを削除するリスクがない場合(入力がトップレベルノードではないことが何らかの形で保証されていると想像してください。また、最初のノードのconstnessが必要であると確信していると想像してください。リスト内の他のノードの恒常性を意味するものではありません)、次のように書くことができます:

NODE *top_level(const NODE *input)
{
  NODE *result = input->parent;
  while (result->parent != nullptr)
    result = result->parent;

  return result;
}

const_cast関数自体を責任あるconst-safe市民にするために必要な仮定を追加すると、は不要になりました。システムは動作します!;-)

于 2013-02-06T12:24:16.277 に答える
0

少なくともインターフェイスレベルでの通常の解決策は、にオーバーロードしてconst、2つの関数とを提供することNODE const* top_level( NODE const* input )ですNODE* top_level( NODE* input )。コードを複製したくない場合は、を使用const_castして一方を他方の観点から実装できます。

于 2013-02-06T11:55:33.387 に答える