2016-06-23 3 views
2

C++言語では、参照が割り当てられた後で変更することはできません。しかし、私はデバッグの必要性がありました/何かをデバッグするための参照を変更する必要があります。基本的にリファレンス実装を新しいポインタで上書きするためのハックな方法はありますか?変更したいオブジェクトへのアドレスを取得したら、必要なものにキャストして上書きすることができます。私は基礎となる参照インスタンスのメモリアドレスを取得する方法を理解できませんでした。参照を逆参照するために&を使用しても、参照のアドレスではなく、参照によって参照されるオブジェクトのアドレスが得られます。C++リファレンスをどのように変更できますか(任意の手段で)

これは明らかに未定義の動作を呼び出すことに気付きました。これは単なる実験に過ぎません。サードパーティのライブラリには、コードが実行される前に構築されていなかったグローバル参照のバグがあり、参照を自分で設定することで修正できるかどうかを確認したいと思います。この時点で、それが可能であるかどうかを確認することは難題になりました。シンボルテーブルを直接参照することができれば、アセンブリ言語でこれを行うことができます。

私はこれを想像します。これらはグローバルスコープの変数です。

Apple a; 
Apple& ref = a; 

後、私はrefは、新しいオブジェクトインスタンスbを参照し、一人でaを残したいです。

Apple b; 

ref = b; // that doesn't work. that justs sets a=b. 

&ref = &b; // that doesn't work. the compiler complains. 

uint64_t addr = find_symbol_by_any_means_necessary(ref); 
*(Apple**)addr = &b; // this should work if I could get addr 

これは悪い考えです。私はそれが悪い考えであることを知っている。それを挑戦と考えてください。これは仮説を素早くテストするためのデバッグ専用です。私はC++バイナリコードの内部について何かを学びたいと思っています。 (システムページ保護のために不可能な場合は教えてください...参照が聖地に置かれていると、segフォルトが発生する可能性があります)。

(システムはCentOS 7ですが、コンパイラはIntelですが、この実験ではgccを使用できます)。

+0

あなたはうまくいきませんか?このコードを試してください: 'Apple a;アップル&a_ref;アップルb;あなたが 'a_ref'が' b'を指していることを確かめるでしょう。単にデータをコピーするだけではありません。もしあなたが 'a = b'をしたら、あなたはそうではないでしょう。 –

+0

@QPaysTaxes、参照で代入演算子を使用すると、参照先オブジェクトが割り当てられます。 – chris

+0

@QPaysTaxes:指定したコード例はコンパイルされません。 'Apple &a_ref;'は無効です。次のコード: 'Apple a;アップル&a_ref = a; a_ref = b; 'は、Apple Aとあらゆる点で同等です。 a = b; ' –

答えて

4

スタンドアロンの参照変数が参照するオブジェクトをリダイレクトする方法はないと思います。

参照がメンバー変数としてstructに含まれている場合は、参照変数が参照するオブジェクトを簡単に変更できます。これはUBの可能性が高いですが、現在のバージョンのg ++​​、g ++ 4.8.4で動作します。

ここでは、メソッドを示すサンプルプログラムを示します。

#include <iostream> 
#include <cstring> 

struct Foo 
{ 
    int& ref; 
}; 

int main() 
{ 
    int a = 10; 
    int b = 20; 

    Foo foo = {a}; // foo.ref is a reference to a 
    std::cout << foo.ref << std::endl; 

    // Use memcpy to change what foo.ref references 
    int* bPtr = &b; 
    std::memcpy(&foo, &bPtr, sizeof(bPtr)); 

    // Now, foo.ref is a reference to b 
    std::cout << foo.ref << std::endl; 

    // Changing foo.ref changes b 
    foo.ref = 30; 
    std::cout << b << std::endl; 
} 

出力:

10 
20 
30 
+1

+1私は参照を変更することはできませんが、コードは壊れます...しかし、あなたは私に考えを与えました。参照の前に犠牲変数*を置き、犠牲変数と参照が順次メモリに置かれると仮定します。犠牲変数のアドレスを取得し、refereneに到達するために数バイトオフセットを追加します... –

0

参照がreseatableないという事実は、最適化の多くを可能にするので、それは、一般的にはできません。

たとえば、参照はしばしばポインタとして実装されますが、コンパイラはしばしば固定オフセットを使用することに気付くかもしれません。したがって、ポインタを格納する以外に、コンパイラはポインタとオフセットを格納することを決定することがあります。ポインターとオフセットだけを保存することもできます。

もう1つの最適化は、リファレンスをアドレスとしてCPUレジスタに格納することです。変更できないため、コンパイラはリロードする必要はありません。

あなたがアセンブリで変更することができるという記述は、誤解を招くものです。最適化後に参照の表現が何であるか分かりません。この最適化は状況に依存します。

関連する問題