2012-07-16 16 views
10

Visual Studio 2012RCには、非標準の拡張機能がいくつかあります。たとえば、次のコードをコンパイルします。右端値から左端値への変換Visual Studio

#include <string> 

using namespace std; 

void value(string& value) 
{ 
    value = "some"; 
} 

int main() 
{ 
    value(string("nice")); 
} 

これは非標準の拡張であると警告します。だから、私は理解したい、それが本当で、どのようにコードが変換されるのか(rvalue-referenceかconst_castのconst参照)を知りたいですか?

+1

AFAIK、Visual Studio 2010(および多分2008年)もこの動作をサポートしています。 VC++コンパイラは、一時的なオブジェクトの変更を許可します。 – flamingo

+0

これは最高の悪いスタイルであり、最悪の場合はバグが発生しやすいことに注意してください(["一時的な変更は気にしないでください]"(http://stackoverflow.com/a/1565811/768469)) – Nemo

+1

@ flamingo:C++で一時的なオブジェクトを変更することは決して不法ではありません。 C++では一時変数の非const * modification *メンバ関数を常に呼び出すことが許されています。しかし、 "直接"構文を使用して非const参照を付けることは不正です。私の答えに示されているように、前者は実際に後者を回避することができます。 – AnT

答えて

8

クラス型の一時オブジェクトは、依然としてオブジェクトです。これはメモリのどこかにあります。つまり、コンパイラーに参照を付けることができることは何も珍しいことではありません。物理的なレベルでは、それがconst参照であるか非const参照であるかに違いはありません。言い換えれば、そのような場合には、言語制限は純粋に概念的で人工的である。コンパイラは単にその制限を無視します。ここで何か「変身」する必要はありません。リファレンスは、そのオブジェクトが常駐している場所に直接オブジェクトに直接添付されます。

基本的に、そのthisポインタの値へのアクセスを外部ワードを提供するクラス(または*thisに左辺値アクセスの)行動が直ちにかつ容易に上記のコードである

struct S { 
    S& get_lvalue() { return *this; } 
}; 

void foo(S& s); 
... 

foo(S().get_lvalue()); 

シミュレートすることができます完全に合法であり、前述の制限を回避します。 MSVC++の動作はこれと同等であると考えることができます。

+0

ありがとうございます。面白い。受け入れられました。 – ForEveR

+1

関数の外側に一時変数を格納すると、これがUBにつながる可能性がありますか? – Guillaume07

+0

@ Guillaume07:あなたはそれを言い換えることができますか?私はあなたが「株」の意味を理解していません。 – AnT

3

それは参照ツーconst const性なしに(またはC++ 11右辺値参照)であったかのように基本的に、VSは、どこかの空間を割り当てし、それを基準点を聞かせて、

あなたは

プロパティの下/Za(言語拡張を無効にする)コンパイラスイッチで、この動作を無効にすることができます - 私の記憶が正しければ>言語

- > C/C++。

+0

ありがとうございます。いい答えだ。受け入れられますが、正しいコードが(C++ 11では)コンパイルされないため、/ ZAを有効にするのは悪いことです。 – ForEveR

+0

AndreyTの回答がより役に立ちますので、受け付けません – ForEveR

3

標準のC++では、一時的な(rvalue/string("nice"))を非const参照(lvalue)にバインドすることはできませんが、Microsoftコンパイラで許可されます。この警告は、コードが拡張のためにコンパイルされており、他のコンパイラではコンパイルされないことを伝えています。