18

一般に、範囲ベースのループの一時的なライフタイムはforループ全体に拡張されることを知っています ( C++11: The range-based for statement: "range-init"lifetime?を読みました)。したがって、次のようなことを行うことは一般的に問題ありません。

for (auto &thingy : func_that_returns_eg_a_vector())
  std::cout << thingy;

QListQtのコンテナと似ていると思ったことをしようとすると、メモリの問題につまずいています:

#include <iostream>
#include <QList>

int main() {
  for (auto i : QList<int>{} << 1 << 2 << 3)
    std::cout << i << std::endl;
  return 0;
}

ここでの問題は、valgrind がQListクラス内のどこかで無効なメモリ アクセスを示すことです。ただし、リストが変数に格納されるように例を変更すると、正しい結果が得られます。

#include <iostream>
#include <QList>

int main() {
  auto things = QList<int>{} << 1 << 2 << 3;
  for (auto i : things)
    std::cout << i << std::endl;
  return 0;
}

ここで私の質問は次のとおりです。たとえば、未定義の動作をもたらす最初のケースで何かばかげたことをしているのでしょうか(自分でこれに答えるためにC++標準を読んだ経験が十分ではありません)? それとも、これは私がどのように使用するかQList、またはどのようQListに実装されているかの問題ですか?

4

2 に答える 2

12

C++11 を使用しているため、代わりに初期化リストを使用できます。これは valgrind を渡します:

int main() {
  for (auto i : QList<int>{1, 2, 3})
    std::cout << i << std::endl;
  return 0;
}

この問題は、範囲ベースの for または C++11 に完全に関連しているわけではありません。次のコードは、同じ問題を示しています。

QList<int>& things = QList<int>() << 1;
things.end();

また:

#include <iostream>

struct S {
    int* x;

    S() { x = NULL; }
    ~S() { delete x; }

    S& foo(int y) {
        x = new int(y);
        return *this;
    }
};

int main() {
    S& things = S().foo(2);
    std::cout << *things.x << std::endl;
    return 0;
}

無効な読み取りは、式(S()または)からの一時オブジェクトがQList<int>{}宣言の後に破棄されるためです (C++03 および C++11 §12.2/5 に従って)。その一時オブジェクト。したがって、解放されたメモリの内容を参照しています。foo()operator<<

于 2012-04-14T12:56:53.827 に答える
7

operator <<コンパイラは、 への 3 回の呼び出しの結果である参照が一時オブジェクトにバインドされていることを認識できない可能性があるQList<int>{}ため、一時オブジェクトの寿命は延長されません。コンパイラは、型を除いて、関数の戻り値について何も知りません (また、知ることが期待できません)。参照の場合、何にバインドできるかわかりません。寿命を延ばすルールが適用されるためには、バインディングが直接的でなければならないことは確かです.

リストは一時的なものではないため、これは機能するはずです。

#include <iostream>
#include <QList>

int main() {
  auto things = QList<int>{};
  for (auto i : things << 1 << 2 << 3)
    std::cout << i << std::endl;
  return 0;
}

バインディングが直接であるため、これは機能するはずです。したがって、ルールを適用できます。

#include <iostream>
#include <QList>

int main() {
  for (auto i : QList<int>{1, 2, 3})
    std::cout << i << std::endl;
  return 0;
}
于 2012-04-14T13:10:58.173 に答える