如何更改 C++ 的变量参考是指?

发布于 2024-12-09 04:40:36 字数 135 浏览 1 评论 0原文

如果我有这个:

int a = 2;
int b = 4;
int &ref = a;

如何使 ref 在此代码之后引用 b

If I have this:

int a = 2;
int b = 4;
int &ref = a;

How can I make ref refer to b after this code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

如痴如狂 2024-12-16 04:40:36

这是不可能的,这是设计使然的。引用不能反弹。

This is not possible, and that's by design. References cannot be rebound.

昔梦 2024-12-16 04:40:36

在 C++11 中,出现了新的 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);
}

这对于在容器中存储引用也很有用。

With C++11 there is the new(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);
}

This is also useful for storing references in containers.

自此以后,行同陌路 2024-12-16 04:40:36

您无法重新分配引用,但如果您正在寻找提供与此类似功能的东西,您可以使用指针代替。

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

You can't reassign a reference, but if you're looking for something that would provide similar abilities to this you can do a pointer instead.

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.

You can get or set the value within pointer with: 

*ptr = 5;     //set
int c = *ptr; //get
薯片软お妹 2024-12-16 04:40:36

从形式上来说,这是不可能的,因为这是设计所禁止的。实际上,如果你想破解它,这是可能的。

引用存储为指针,因此只要您知道如何获取其地址,就可以随时更改它指向的位置。同样,当您无权访问时,您也可以更改 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

然而,这样做被认为是危险的,因此不推荐,因为它违背了参考的最初目的。 C/C++语言中reference的设计目的是禁止在编程层面改变其内容。因此,如果最终您需要更改其值,那么您应该考虑将该变量定义为指针。此外,这里提出的解决方案假设引用被实现为指针(在大多数编译器实现中都是如此,但不是全部)。因此,当底层实现不是指针时,它将不起作用(在这种情况下会导致程序崩溃)。

Formally speaking, that is impossible as it is forbidden by design. Practically speaking, that is possible if you want to hack it.

A references is stored as a pointer, so you can always change where it points to as long as you know how to get its address. Similarly, you can also change the value of const variables, const member variables or even private member variables when you don't have access to.

For example, the following code has changed class A's const private member reference:

#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;
}

Program output:

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

As you can see that a.i1 initially points to i, after the change, it points to j.

However, doing so is considered as dangerous and thus unrecommended, because it defeats the original purpose of reference. The design purpose of reference in C/C++ language is to forbid alterations of its content at programming level. So if it ends up that you need to alter its value, then you should consider define that variable as a pointer instead. Moreover, the solution proposed here is assuming that the reference is implemented as a pointer (which is true in most of the compiler implementations but not all). So it will NOT work when the underlying implementation is not a pointer (and it will cause your program to crash in that case).

长安忆 2024-12-16 04:40:36

您无法重新分配参考。

You cannot reassign a reference.

阳光下的泡沫是彩色的 2024-12-16 04:40:36

以你想要的方式这是不可能的。 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.
}

That's not possible in the way you want. C++ just doesn't let you rebind what a reference points to.

However if you want to use trickery you can almost simulate it with a new scope (NEVER do this in a real program):

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.
}
顾挽 2024-12-16 04:40:36

您可以使用新的放置非常容易地创建参考包装器:

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

You can make a reference wrapper very easy using the placement 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
天涯离梦残月幽梦 2024-12-16 04:40:36

这是可能的。因为在底层,引用是一个指针。
以下代码将打印“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("%s\n", rc.ref.c_str());
}

This is possible. Because under the hood, reference is a pointer.
The following code will print "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("%s\n", rc.ref.c_str());
}
我的鱼塘能养鲲 2024-12-16 04:40:36

正如其他答案所说,这是不可能的。

但是,如果您将引用存储在 classstruct 中,则可以使用 Placement new 重新创建整个内容,从而重新绑定引用。正如 @HolyBlackCat 指出的,不要忘记使用 std::launder 来访问 re -创建的对象或使用从放置新返回的指针。考虑我的示例:

#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;
}

demo

输出为:

&ref_container.ref = 0x7ffdcb5f8c44
&a = 0x7ffdcb5f8c44

&ref_container = 0x7ffdcb5f8c38
new_ref_container = 0x7ffdcb5f8c38
&new_ref_container.ref = 0x7ffdcb5f8c40
&b = 0x7ffdcb5f8c40

It is impossible, as other answers state.

However, if you store your reference in a class or struct, you could re-create the whole thing using placement new, so the reference is re-bound. As @HolyBlackCat noted, don't forget to use std::launder to access the re-created object or use the pointer returned from the placement new. Consider my example:

#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;
}

demo

The output is:

&ref_container.ref = 0x7ffdcb5f8c44
&a = 0x7ffdcb5f8c44

&ref_container = 0x7ffdcb5f8c38
new_ref_container = 0x7ffdcb5f8c38
&new_ref_container.ref = 0x7ffdcb5f8c40
&b = 0x7ffdcb5f8c40
临走之时 2024-12-16 04:40:36

虽然这是一个坏主意,因为它违背了使用引用的目的,但可以直接更改引用

const_cast< int& >(ref)=b;

Although its a bad idea as it defeats the purpose of using references, it is possible to change the reference directly

const_cast< int& >(ref)=b;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文