更新值还是更改指针更好

Is it better to update the value or change the pointer?

本文关键字:指针 更好 更新      更新时间:2023-10-16

C++

是更新指针的值更好,还是将指针更改为指向其他对象更好?

假设我们有两个类:球和坐标。

class ball
{
    Coordinates *ballCurrent;
    public:
        ball(int);
        ~ball();
        void setLoc(Coordinates&); // OR void setLoc(int, int);
};
class Coordinates
{
    int x, y;
    public:
        Coordinates(int, int);
        void setCoordinates(int, int);
};

对于ball类中的setLoc方法,哪些参数应该更好?使用(*ballCurrent).setCoordinates(int,int)或使用(ballCurrent.).setLoc((new Coordinations(int,int.))设置Loc会更好吗?如果可能的话,请详细说明每种情况的原因。

更新指针的值更好还是更改指针更好指向其他东西?

这不是一个没有上下文就可以回答的问题。知道一个对象是不可变的通常很有用——只要你有一个指向该对象的指针,这个对象就不会在你的眼皮底下改变。例如,如果一个函数或方法将指向不可变类型的指针作为参数,那么您就知道可以将对象传递给该函数,而不必担心该函数会更改对象。

另一方面,可变对象也有自己的位置。首先,您有时希望能够分几个步骤构建一个对象,而不是一次完成所有操作,并且您可能不希望为了到达最终对象而必须在一路上创建几个中间对象。

所以,这取决于上下文。我看到你提供了一个简单的例子,但我认为即使是你的例子也不一定有正确的答案。这取决于什么对你来说很重要,以及有问题的对象将如何与系统的其他部分交互。我想,我会倾向于可变对象,因为在游戏中,可能有几个对象需要了解球。如果移动球的唯一方法是创建一个新球,并将其传递给所有其他关心它的对象,那么,这很容易成为一个巨大的问题。不过,坐标对象很容易是不可变的——任何需要知道球位置的人都应该向球询问它的位置。一旦他们得到了它,他们可能会期望位置不会每隔几毫秒就改变一次。如果你不让坐标对象不可变,那么处理这个问题的另一种方法是,每当有人提出要求时,球就复制它的位置,并分发副本,而不是返回指向它自己位置对象的指针。

如果可以的话,我可能会这样写:

class ball
{
    Coordinates coordinate_;     // better name than ballCurrent?
    public:
        explicit ball(int)       // add explicit to avoid implicit converting
        : coordinate_(0,0)       // initialize corrdinate_ properly
        {
        }
        ~ball();
        void setLoc(const Coordinates& co) // add const
        {
           coordinate_ = co;
        }
        void setLoc(int x, int y)
        {
           coordinate_.setCoordinates(x,y);
        }
};

无需担心动态内存问题,setLoc可以通过两种方式通过函数重载。没有疯狂的指针,没有烦恼。

如果您使用一个新对象,它将需要为自己分配内存,还需要初始化(构造函数运行、属性分配等)。与仅仅更改您已经拥有的对象(以及您为此目的创建的对象)的值相比,这是一个很大的开销。

此外,如果你创建了一个新对象,你需要释放上一个指针的内存,这也是开销。。。所以只需更改现有对象即可。

只需更改所指向对象的值。每次更新值时都创建一个全新的对象是没有意义的。

一种情况是,如果Coordinates有一个常量x和y值,并且没有setCoordinations函数,则可能需要创建一个全新的对象,而不是只更改值。但如果你需要经常更新坐标,那么这很可能是一个糟糕的设计决定。

也不是这样:

(*ballCurrent).setCoordinates(int, int);

你可以使用这个:

ballCurrent->setCoordinate(int, int);

它做了同样的事情,但更容易写,很多人会发现它更可读。

SetLoc(int,int)的情况下,您正在ballCoordinates之间创建对Coordinates构造函数的依赖关系,更重要的是,对它所代表的内容的依赖关系。如果构造函数签名发生更改,则必须将这些更改转移到ball::SetLoc。这个参数在一般情况下是有效的,在这种情况下,您确实希望避免传递一组参数来初始化对象组件。

在这种特殊的情况下,Coordinates体现了空间中的一个位置,可能应该配备一套操作它的方法,以避免其实现细节渗透到程序的其余部分。如果您希望移动到三维坐标系,理想情况下,您所需要更改的只是构造函数调用和类实现。因此,您确实希望将类外的必要更改减少到最低限度,这意味着要避免前面解释的问题。

您将提供两种不同的解决方案来设置ball对象的位置。在实践中,这些解决方案会出现吗?在一个琐碎的程序中,球的位置被硬编码,这是一种可能性,任何一种解决方案都可能奏效。但在更复杂的软件中,球的位置可能最初是由配置文件设置的,任何后续的位置更新都是在一些非琐碎的计算之后完成的。在这种情况下,将所有与类中的坐标相关的逻辑封装起来,并避免传递(int, int)参数,会更容易维护。

如果您担心内存分配开销(例如,函数返回结果生成的临时内存),有一些方法可以通过明智地使用常量、引用甚至指针来减轻这些开销,并定义合理的复制构造函数。