如何更改c++引用所引用的变量?
How can I change the variable to which a C++ reference refers?
如果我有这个:
int a = 2;
int b = 4;
int &ref = a;
在这段代码之后如何使ref
引用b
?
这是不可能的,这是设计的。引用不能反弹
在c++ 11中有一个新的(ish) std::reference_wrapper
#include <functional>
int main() {
int a = 2;
int b = 4;
auto ref = std::ref(a);
//std::reference_wrapper<int> ref = std::ref(a); <- Or with the type specified
ref = std::ref(b);
}
这对于在容器中存储引用也很有用。
你不能重新分配引用,但如果你正在寻找能够提供类似功能的东西,你可以做一个指针代替。
int a = 2;
int b = 4;
int* ptr = &a; //ptr points to memory location of a.
ptr = &b; //ptr points to memory location of b now.
您可以使用
获取或设置指针内的值:*ptr = 5; //set
int c = *ptr; //get
不能重新分配引用。
从形式上讲,这是不可能的,因为这是设计所禁止的。实际上,如果你想破解它,这是可能的。
A引用是以指针的形式存储的,所以只要你知道如何得到它的地址,你就可以随时改变它指向的位置。类似地,当无法访问const变量、const成员变量甚至私有成员变量时,也可以更改const变量的值。
例如,下面的代码改变了类A的const私有成员引用:#include <iostream>
using namespace std;
class A{
private:
const int &i1;
public:
A(int &a):i1(a){}
int geti(){return i1;}
int *getip(){return (int*)&i1;}
};
int main(int argc, char *argv[]){
int i=5, j=10;
A a(i);
cout << "before change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
i=6; cout << "setting i to 6" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
*(int**)&a = &j; // the key step that changes A's member reference
cout << endl << "after change:" << endl;
cout << "&a.i1=" << a.getip() << " &i=" << &i << " &j="<< &j << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
j=11; cout << "setting j to 11" << endl;
cout << "i=" << i << " j=" <<j<< " a.i1=" << a.geti() << endl;
return 0;
}
程序输出:
before change:
&a.i1=0x7fff1b624140 &i=0x7fff1b624140 &j=0x7fff1b624150
i=5 j=10 a.i1=5
setting i to 6
i=6 j=10 a.i1=6
after change:
&a.i1=0x7fff1b624150 &i=0x7fff1b624140 &j=0x7fff1b624150
i=6 j=10 a.i1=10
setting j to 11
i=6 j=11 a.i1=11
可以看到a。I1 最初指向i,修改后指向j。
然而,这样做被认为是危险的,因此不推荐,因为它违背了引用的原始目的。reference
在C/c++语言中的设计目的是禁止在编程层面对其内容进行修改。因此,如果最终需要更改其值,则应该考虑将该变量定义为指针。此外,这里提出的解决方案是假设引用是作为指针实现的(这在大多数编译器实现中是正确的,但不是全部)。因此,当底层实现不是指针时,它将不起作用(在这种情况下,它将导致程序崩溃)。
这不是你想要的方式。c++不允许重新绑定引用指向的对象。
但是,如果你想使用技巧,你几乎可以用一个新的作用域来模拟它(永远不要在实际程序中这样做):
int a = 2;
int b = 4;
int &ref = a;
{
int& ref = b; // Shadows the original ref so everything inside this { } refers to `ref` as `b` now.
}
您可以使用new:
位置很容易地创建一个引用包装器template< class T >
class RefWrapper
{
public:
RefWrapper( T& v ) : m_v( v ){}
operator T&(){ return m_v; }
T& operator=( const T& a ){ m_v = a; return m_v;}
//...... //
void remap( T& v )
{
//re-map reference
new (this) RefWrapper(v);
}
private:
T& m_v;
};
int32 a = 0;
int32 b = 0;
RefWrapper< int > r( a );
r = 1; // a = 1 now
r.remap( b );
r = 2; // b = 2 now
这是可能的。因为在底层,引用是一个指针。下面的代码将打印"hello world"
#include "stdlib.h"
#include "stdio.h"
#include <string>
using namespace std;
class ReferenceChange
{
public:
size_t otherVariable;
string& ref;
ReferenceChange() : ref(*((string*)NULL)) {}
void setRef(string& str) {
*(&this->otherVariable + 1) = (size_t)&str;
}
};
void main()
{
string a("hello");
string b("world");
ReferenceChange rc;
rc.setRef(a);
printf("%s ", rc.ref.c_str());
rc.setRef(b);
printf("%sn", rc.ref.c_str());
}
这是不可能的,正如其他答案所述。
但是,如果您将引用存储在class
或struct
中,则可以使用placement new重新创建整个内容,因此引用被重新绑定。正如@HolyBlackCat所指出的,不要忘记使用std::launder
来访问重新创建的对象或使用从位置new返回的指针。考虑我的例子:
#include <iostream>
struct A {
A(int& ref) : ref(ref) {}
// A reference stored as a field
int& ref;
};
int main() {
int a = 42;
int b = 43;
// When instance is created, the reference is bound to a
A ref_container(a);
std::cout <<
"&ref_container.ref = " << &ref_container.ref << std::endl <<
"&a = " << &a << std::endl << std::endl;
// Re-create the instance, and bind the reference to b
A* new_ref_container = new(&ref_container) A(b);
std::cout <<
// &ref_container and new_ref_container are the same pointers
"&ref_container = " << &ref_container << std::endl <<
"new_ref_container = " << new_ref_container << std::endl <<
"&new_ref_container.ref = " << &new_ref_container->ref << std::endl <<
"&b = " << &b << std::endl << std::endl;
return 0;
}
输出为:
&ref_container.ref = 0x7ffdcb5f8c44
&a = 0x7ffdcb5f8c44
&ref_container = 0x7ffdcb5f8c38
new_ref_container = 0x7ffdcb5f8c38
&new_ref_container.ref = 0x7ffdcb5f8c40
&b = 0x7ffdcb5f8c40
虽然这是一个坏主意,因为它违背了使用引用的目的,但可以直接更改引用
const_cast< int& >(ref)=b;
相关文章:
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 多个"常量引用"变量可以共享同一个内存吗?
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- C++方法中的引用变量
- 作为赋值(增加引用变量)C++的左操作数所需的左值
- 使用更改此变量的函数在同一行中打印引用变量
- 将延迟变量分配给引用变量
- 如何通过引用获取引用变量的地址?
- 将引用变量传递给函数
- C++中引用变量的内存?
- 按名称存储和引用变量列表
- 返回一个C++引用变量 VS 返回一个变量
- c++ 在 if 语句中分配引用变量
- 引用变量何时合适,为什么?你能解释一下实际的语法和位置吗?
- C++ - 将一个变量分配给另一个变量和将变量分配给引用变量有什么区别?
- 在类范围内声明时,应在 C++14 中引用变量模板
- 当引用变量的引用"死亡"时,它会发生什么?
- 将非按引用变量分配给返回按引用的函数,反之亦然
- 引用变量如何存储在mem中
- 引用变量存储在哪里