C ++语言不允许在分配引用后更改引用。但是,我有调试需要/希望更改引用以帮助调试某些东西。是否存在基本上用新指针覆盖引用实现的hacky方法?获得要更改的对象的地址后,可以将其转换为您想要的任何内容并覆盖它。我无法弄清楚如何获取底层引用实例的内存地址;使用&
取消引用引用并不会为您提供引用的地址,而是引用所指向的对象的地址。
我意识到这显然会调用未定义的行为,这只是一个实验。第三方库有一个全局引用的错误,在执行代码之前没有构造,我想看看我是否可以通过自己设置引用来修复它。在这一点上,看看它是否可能成为一个挑战。如果您可以直接引用符号表,我知道您可以用汇编语言执行此操作。
我想象这样的事情。这些是全局范围的变量。
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 ++二进制代码的内部结构。 (请告诉我,由于系统页面保护是不可能的......如果引用放在圣地,我想你可能会遇到段错误)。
(系统是CentOS 7,编译器是Intel,虽然我可以使用gcc进行此实验)。
答案 0 :(得分: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 :(得分:0)
通常不可能,因为引用不可重载的事实允许大量优化。
例如,引用通常实现为指针,但编译器也可能注意到您经常使用固定偏移量。因此,除了存储指针之外,编译器还可以决定存储指针加上偏移量。它甚至可能决定只存储指针和偏移量。
另一个优化是将引用存储为CPU寄存器中的地址。由于它无法更改,编译器无需重新加载它。
所以你的声明,你可以在汇编中改变它是相当误导。您不知道在优化之后引用的表示是什么,并且此优化将在情境上依赖。