【问题标题】:Change 'this' pointer of an object to point different object将对象的“this”指针更改为指向不同的对象
【发布时间】:2013-08-16 03:45:14
【问题描述】:
class C{
   //methods and properties
}

void C::some_method(C* b){
    delete this;
    this = b;     
}

编译时出现以下错误:

error: lvalue required as left operand of assignment

我的意图: 假设有 C 类的对象 a 和 b。C 类的内容可能非常庞大,逐个字段的复制可能非常昂贵。我希望以经济的方式将“a”的所有内容替换为“b”。

默认的复制构造函数会完成预期的任务吗?

我发现了一个叫做“移动构造函数”的东西 http://akrzemi1.wordpress.com/2011/08/11/move-constructor/

也许,它可能会得到我想要的效果。

【问题讨论】:

  • 你确定你可以做这样的事情吗??
  • 确实如此。您刚刚发现this 不可重新分配,因为这没有任何意义。你有问题吗?
  • this 无法更改。您要实现的更高层次的目标是什么?
  • 你到底为什么要这么做?你想要完成什么?。交换两个对象?。
  • @Kevin 你是对的。我想将 b 中的任何内容复制到当前对象。

标签: c++ this


【解决方案1】:

this-pointer 是一个隐式指针,指向您正在其上下文中工作的对象,您不能重新分配它。

根据 Stroustrup 的圣经(The C++ Programming Language, 3rd edition I have)this 表示为

C * const this

意味着你有一个指向你的类C常量指针,所以如果你试图改变它,编译器会报错。

编辑:

正如我更正的那样,上述表达式没有完全正确地描述this,因为this 实际上是一个右值。

【讨论】:

  • 我不确定this 是否为常量,感谢您提供的信息。
  • 引用说明了它是如何“实施”的。形式上,this 不是对象;它是一个右值表达式。
  • @kol 不,你不能。要更改值,您需要某种左值表达式。而且由于this 是一个右值,并且没有类类型,因此无法从中获取左值。
  • 不是const,它是一个右值。两者是完全不同的东西。在这种情况下,您可以将它们视为有些等价,但总的来说,它们根本不一样。
  • @bash.d:James Kanze 的回答清楚地引用了这个问题上的标准。
【解决方案2】:

您无法更改this 指向的内容。我也不知道你为什么要这样做。

【讨论】:

  • @kol 实际上你不能,除非你的编译器被严重损坏(或者严重老——你可以直到 1990 年之前,当重载 operator new 的可能性被添加到语言)。
【解决方案3】:

您不能为this 分配不同的值,因为它指向对象本身,这没有任何意义。 您可以实例化一个新对象并改用其隐式 this 指针。

另外,如果你尝试复制对象,你可以覆盖operator=

class Foo
{
  public:
    [...]
    Foo& operator=(const Foo& foo);
}

int main()
{
 Foo foo;
 foobar = foo; //invoke operator= overwrited method
}


【讨论】:

    【解决方案4】:

    错误提示“您不能将b 分配给this”。据我所知,this 是您无法更改的,因为它不是实际的指针,而是自引用。

    【讨论】:

    • 它是一个指针,它基本上是ClassType* const this,这意味着它不能被修改为指向其他东西,并且由于它是一个prvalue,它不能在一个表达式的lhs上。
    • @Rapptz 它有一个指针类型,但它不是 const,因为它是一个右值,并且非类类型的右值没有 cv 限定符.
    • 非类类型右值的另一个例子是什么?
    【解决方案5】:

    引用标准:

    在非静态 (9.3) 成员函数的主体中,关键字 this 是一个prvalue 表达式,其值为 调用函数的对象。

    “prvalue”是纯右值,类似于423.14159。 以同样的方式你不能做类似42 = x的事情,你不能 分配给this;在这两种情况下(至少在概念上),有 不是值可以改变的对象。

    我真的很好奇如果你期望发生什么 我写的是这样的:

    int
    main()
    {
        C c1;
        C c2
        c1.some_method( &c2 );
    }
    

    您是否期望c1 的地址会奇迹般地出现 更改,并且 c1c2 是同一个对象的别名? (而c1.some_method( NULL ) 更有趣。)

    【讨论】:

    • @kol 实际上,您不能,而且您的答案根本不正确。这里的标准很清楚:this 是纯右值(或 C++11 之前的右值),分配给右值是非法的,并且没有 no 方法来获取左值来自非类类型的右值。
    • @JamesKanze 是的,我希望他们成为别名。
    • @UtkristAdhikari 但这显然是不可能的,因为成员函数中的代码无法更改main 中符号的含义。在main 中,c1 指定了一个非常具体的实体,关联符号 -> 实体在编译和链接时完全由编译器和链接器管理。
    【解决方案6】:

    只需使用通常的方法而不是黑魔法和UB:

    C* c1 = new C();
    C* c2 = new C();
    
    // do some work perhaps ...
    
    delete c1;
    c1 = c2;
    

    现在 c1 是你想要的 c2 的别名。但在清理内存时要小心,以免最终删除对象两次。您可能会考虑使用智能指针...

    【讨论】:

    • 赋值必须发生在 c1 的方法中
    • 这段代码不是任何事情的常用方法。如果您只是希望 c1 指向与 c2 相同的对象,则没有理由为 c1 新建和删除对象。只需立即将 c2 分配给 c1。此外,裸 new 和 delete 不是异常安全的(即使您没有使用内置的 C++ 异常处理机制,异常安全也很重要)。至少,使用 unique_ptr 来保存动态分配的对象。但是除非你有充分的理由,否则你不应该首先动态分配。创建别名的常用方法是通过引用。
    猜你喜欢
    • 2011-11-12
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多