【问题标题】:Making changes to object state from within a function从函数中更改对象状态
【发布时间】:2013-10-27 15:16:25
【问题描述】:

我不得不简化一些代码来提出这个问题。但是,在下面的代码中,我没有将 x 声明为引用类型这一事实是否意味着一旦函数退出,我对递减的更改将被“遗忘”?

解决此问题的最明智方法是将x 声明为AnotherClass& x

void MyClass::myFunc(unordered_map<int, AnotherClass>* dictionary, int z, int y){

    AnotherClass x = dictionary->at(z);

    //Does this change on x get "forgotten" in terms of what dictionary stores
    //once myFunc() has finished, because x is not a reference/pointer type?
    x.changeSomething(y--);
}


class MyClass{
    public:

    private:
        myFunc(unordered_map<int, AnotherClass>* dictionary, int z);
        unordered_map<int, AnotherClass>* dictionary

};

【问题讨论】:

    标签: c++ pointers reference pass-by-reference


    【解决方案1】:

    正确。 xdictionary 元素的副本。您正在对函数本地的副本应用更改。您应该在调用方看不到任何影响。您可以参考,也可以直接对at 的调用结果采取行动:

    dictionary->at(z).changeSomething(z--);
    

    请注意,这与函数内部的代码无关。

    【讨论】:

    • 只是一个额外的问题,如果我没有修改字典但我正在创建一个新的 AnotherClass 对象以插入到字典中 - 我不需要将新的 AnotherClass 对象声明为引用类型,它可以只是 AnotherClass new_obj?
    • @user997112 我不确定我是否理解这个问题,但也许这会澄清一些事情:1)引用必须引用一些东西。它只是对象的别名。 2)当您将对象放入地图时,地图会制作自己的该对象的副本。所以你可以给地图一个对另一个对象的引用,但这没有区别,因为地图会复制它所引用的对象。
    • 我想你还是回答了它——我不能声明一个引用类型的新字典元素,因为正如你所说,你需要一个现有元素,而我问的是一个新元素进入字典。
    【解决方案2】:

    在 Java 或 C# 等语言中,当您编写 Thing t = s; 时,您实际上是在创建一个别名 t,它引用的内存中的对象与 s 引用的对象相同。然而,在 C++ 中,值和别名是严格分开的:

    • Thing t = s; 是关于制作s副本
    • Thing&amp; t = s; 是关于创建一个别名,该别名引用与s 相同的对象(引用)
    • Thing* t = &amp;s; 是关于创建一个别名,该别名引用与 s 相同的对象(一个指针)

    引用和指针的区别在这里不重要,重要的是副本和别名的区别。

    • 对副本的更改是该副本的本地更改
    • 对象的更改通过别名是该对象本地的,并且通过引用该对象的所有别名可见

    就你的例子而言:

    // Fix 1: take dictionary by *reference* and not by *pointer*.
    void MyClass::myFunc(std::unordered_map<int, AnotherClass>& dictionary, int z, int y){
        // Fix 2: dictionary.at(z) returns a "AnotherClass&"
        // that is an alias to the element held within the dictionary.
        // Make sure not to accidentally make a copy by using that "&"
        // for the type of x.
        AnotherClass& x = dictionary.at(z);
    
        // "x" is now a mere alias, the following call is thus applied
        // to the value associated to "z" within "dictionary".
        x.changeSomething(y--);
    }
    

    注意在这种情况下你可以写dictionary.at(z).changeSomething(y--);;但是有几个缺点:

    • 如果x 被重复使用一次以上,命名它会更清楚。
    • 如果调用的函数/方法有副作用,调用次数很重要,需要加以控制。
    • 从性能的角度来看,避免不必要地反复计算相同的事情总是受欢迎的......但不要过于关注性能;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      • 2020-10-31
      • 2019-08-07
      • 2020-02-28
      • 1970-01-01
      • 2016-10-09
      • 2021-05-09
      相关资源
      最近更新 更多