8

次のコードで「xxY」と表示されるのはなぜですか? ローカル変数は関数全体のスコープ内に存在するべきではありませんか? このような動作を使用できますか、またはこれは将来の C++ 標準で変更されますか?

C++ 標準 3.3.2 によると、「ブロックで宣言された名前はそのブロックに対してローカルです。その潜在的なスコープは、宣言のポイントで始まり、宣言領域の最後で終わります。

#include <iostream>
using namespace std;

class MyClass
{
public:
  MyClass( int ) { cout << "x" << endl; };
  ~MyClass() { cout << "x" << endl; };
};

int main(int argc,char* argv[])
{
  MyClass  (12345);
// changing it to the following will change the behavior
//MyClass m(12345);
  cout << "Y" << endl;

  return 0;
}

回答に基づいて、それMyClass(12345);が式(およびスコープ)であると推測できます。それは理にかなっています。したがって、次のコードは常に「xYx」を出力することを期待しています。

MyClass (12345), cout << "Y" << endl;

そして、そのような置換を行うことが許可されています:

// this much strings with explicit scope
{
  boost::scoped_lock lock(my_mutex);
  int x = some_func(); // should be protected in multi-threaded program
} 
// mutex released here

//    

// I can replace with the following one string:
int x = boost::scoped_lock (my_mutex), some_func(); // still multi-thread safe
// mutex released here
4

4 に答える 4

16

The object created in your

MyClass(12345);

is a temporary object which is only alive in that expression;

MyClass m(12345);

is an object which is alive for the entire block.

于 2009-09-07T10:40:18.473 に答える
8

You're actually creating an object without keeping it in scope, so it is destroyed right after it is created. Hence the behavior you're experiencing.

You can't access the created object so why would the compiler keep it around?

于 2009-09-07T10:39:20.847 に答える
5

あなたの他の質問に答えるために。以下は、コンマ演算子の呼び出しです。MyClassコンストラクターの呼び出しを含む一時的なものを作成します。次に、Y を出力する 2 番目の式cout << "Y" << endlを評価します。次に、完全な式の最後で、デストラクタを呼び出すテンポラリを破棄します。だからあなたの期待は正しかった。

MyClass (12345), cout << "Y" << endl;

以下が機能するためには、括弧を追加する必要があります。これは、コンマが宣言で定義済みの意味を持っているためです。some_funcを返し、intパラメータを取らない関数の宣言を開始し、scoped_lockオブジェクトを に割り当てますx。括弧を使用して、代わりに全体が単一のコンマ演算子式であると言います。

int x = (boost::scoped_lock (my_mutex), some_func()); // still multi-thread safe

次の 2 行は同等であることに注意してください。1 つ目は、コンストラクターの引数として使用して名前のない一時的なオブジェクトを作成しませmy_mutexが、代わりに名前を囲む括弧が冗長になっています。構文に混乱させないでください。

boost::scoped_lock(my_mutex);
boost::scoped_lock my_mutex;

スコープとライフタイムという用語の誤用を見てきました。

  • Scope名前を修飾せずに名前を参照できる場所です。名前にはスコープがあり、オブジェクトはそれらを定義するために使用された名前のスコープを継承します (したがって、標準では「ローカル オブジェクト」と呼ばれることがあります)。一時オブジェクトには名前がないため、スコープがありません。同様に、によって作成されたオブジェクトにnewはスコープがありません。スコープはコンパイル時のプロパティです。この用語は標準で頻繁に誤用されています。この欠陥レポートを参照してください。そのため、本当の意味を見つけるのは非常に混乱しています。

  • Lifetimeランタイム プロパティです。これは、オブジェクトがセットアップされ、使用できるようになったことを意味します。クラス型オブジェクトの場合、ライフタイムはコンストラクターの実行が終了したときに始まり、デストラクターが実行を開始したときに終了します。ライフタイムはスコープと混同されることがよくありますが、これら 2 つのことは完全に異なります。

    一時オブジェクトの有効期間は正確に定義されています。それらのほとんどは、それらが含まれている完全な式の評価後に存続期間を終了します (上記のコンマ演算子や代入式など)。一時オブジェクトは、寿命を延ばす const 参照にバインドできます。例外でスローされるオブジェクトも一時的なものであり、それらのハンドラーがなくなると、その有効期間は終了します。

于 2009-09-07T15:54:38.017 に答える
4

あなたは標準を正しく引用しました。強調させてください:

ブロックで宣言された名前 は、そのブロックに対してローカルです。その潜在的なスコープは、宣言の時点で始まり、宣言領域の終わりで終わります。

実際、あなたは名前を宣言しませんでした。あなたのライン

MyClass (12345);

宣言すら含まれていません!含まれているのは、MyClass のインスタンスを作成し、式を計算し (ただし、この特定のケースでは計算するものは何もありません)、その結果を にキャストし、voidそこで作成されたオブジェクトを破棄する式です。

混乱の少ないことは次のように聞こえます

call_a_function(MyClass(12345));

あなたはそれを何度も見て、それがどのように機能するかを知っていますよね?

于 2009-09-07T10:50:51.807 に答える