代码之家  ›  专栏  ›  技术社区  ›  user997112

从函数中更改对象状态

  •  0
  • user997112  · 技术社区  · 12 年前

    为了提出这个问题,我不得不简化一些代码。然而,在下面的代码中,我没有声明 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
    
    };
    
    2 回复  |  直到 12 年前
        1
  •  3
  •   juanchopanza    12 年前

    对的 x 是的元素的副本 dictionary 。您正在将更改应用于副本,该副本是函数的本地副本。您应该不会在调用方看到任何效果。您可以引用,也可以直接根据调用的结果执行操作 at :

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

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

        2
  •  2
  •   Matthieu M.    12 年前

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

    • 事物t=s; 是关于制作 复制 属于 s
    • Thing& t = s; 是关于创建引用与 s (参考文献)
    • Thing* t = &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 多次重复使用,命名会使其更加清晰。
    • 在调用的函数/方法有副作用的情况下,调用的数量很重要,需要控制。
    • 从性能的角度来看,避免不必要的重复计算同样的东西总是受欢迎的。。。但不要太在意性能;)