C++ 实例化方法中的对象与创建类成员

C++ 实例化方法中的对象与创建类成员,c++,C++,实例化方法中所需的对象与使对象成为类成员相比,有哪些原因 例如,在下面的示例代码中,我有一个类ClassA,我想从另一个类中使用它,比如USer1,它将指向ClassA对象的指针作为成员变量并在其构造函数中实例化;另一方面,User2在使用它之前在方法中实例化ClassA对象。以这种方式与以另一种方式相比,有哪些原因 class ClassA { public: void doStuff(void){ } }; // // this class has ClassA as a

实例化方法中所需的对象与使对象成为类成员相比,有哪些原因

例如,在下面的示例代码中,我有一个类ClassA,我想从另一个类中使用它,比如USer1,它将指向ClassA对象的指针作为成员变量并在其构造函数中实例化;另一方面,User2在使用它之前在方法中实例化ClassA对象。以这种方式与以另一种方式相比,有哪些原因

class ClassA
{
    public:
    void doStuff(void){ }
};

//
// this class has ClassA as a member
//
class User1
{
    public:
        User1()
        {
            classA = new ClassA();
        }

        ~User1()
        {
            delete classA;
        }

        void use(void)
        {
            classA->doStuff();
        }        
    private:
        ClassA *classA;
};

//
// this class uses ClassA only in a method
//
class User2
{
    public: 
        void use(void)
        {
            ClassA *classA = new ClassA();
            classA->doStuff();
            delete classA;
        }    
};

int main(void)
{
    User1 user1;
    user1.use();

    User2 user2;
    user2.use();

    return 0;
}

使其成为班级成员的好处是:

  • 您不必每次都分配实例,这取决于类,可能会非常慢
  • 成员可以存储状态(尽管有些人会说这是个坏主意)
  • 更少的代码
作为旁注,如果您只是在构造函数和析构函数中使用new和delete进行实例化和删除,那么它实际上不应该是指针,而应该是一个成员实例,然后去掉new和delete

有时情况并非如此,例如,当堆栈上分配的类很大时,或者您希望保持类的占用空间尽可能小。但这些都是例外,而不是规则

<> P>还有其他事情要考虑,比如内存碎片,访问连续内存块的优势,以及如何在目标系统上分配内存。没有银弹,只有一般性的建议,对于任何特定的程序,您需要进行测量和调整,以获得最佳性能或克服特定程序的限制

内存碎片是指即使您有很多可用内存,但单个块的大小非常小,当您尝试分配大量内存时,也会出现内存错误。这通常是由于创建和销毁了许多不同大小的对象,其中一些对象还活着。如果您的系统存在内存碎片问题,我建议您彻底分析对象是如何创建的,而不是担心是否有成员会影响系统。但是,以下是当您遇到内存碎片时,四种不同场景的详细情况:

  • 在堆栈上实例化类非常有用,因为它不会导致整体内存碎片
  • 将其创建为值成员可能会导致问题,因为它可能会增加对象的总体大小,因此当您进入碎片场景时,对象可能太大而无法创建
  • 创建对象并存储指向该对象的指针可能会增加内存碎片
  • 在堆上分配和在使用结束时删除可能会增加内存碎片,如果在使用后分配了其他内容
访问连续内存的优点是缓存未命中被最小化,因此我的感觉是,将对象作为值成员会更快,但由于许多事情依赖于许多其他变量,这可能是完全错误的。和往常一样,在绩效方面,要衡量

内存通常与特定的边界对齐,例如4字节对齐,或2个块的幂。因此,根据您分配其中一个对象时对象的大小,它可能会占用比您预期更多的内存,如果您分配的对象包含任何成员,则可能会显著改变类的内存占用(如果它是值成员),或者如果它不是值成员,则可能根本不会增加它,虽然有一个指向它的指针肯定会增加指针大小的足迹,这可能会导致显著增加。在堆或堆栈上创建类都不会影响使用类的大小。和往常一样,如果它会影响你的程序,你需要在目标系统上进行测量,看看会有什么影响

如果构造函数/析构函数执行某些操作(例如文件句柄、打开文件和关闭文件),那么您可能只希望在函数中使用它。但是,指针通常不是必需的

void use(void)
{
    ClassA classA;
    classA.doStuff();
} //classA will be destructed at end of scope 

使其成为班级成员的好处是:

  • 您不必每次都分配实例,这取决于类,可能会非常慢
  • 成员可以存储状态(尽管有些人会说这是个坏主意)
  • 更少的代码
作为旁注,如果您只是在构造函数和析构函数中使用new和delete进行实例化和删除,那么它实际上不应该是指针,而应该是一个成员实例,然后去掉new和delete

有时情况并非如此,例如,当堆栈上分配的类很大时,或者您希望保持类的占用空间尽可能小。但这些都是例外,而不是规则

<> P>还有其他事情要考虑,比如内存碎片,访问连续内存块的优势,以及如何在目标系统上分配内存。没有银弹,只有一般性的建议,对于任何特定的程序,您需要进行测量和调整,以获得最佳性能或克服特定程序的限制

内存碎片是指即使您有很多可用内存,但单个块的大小非常小,当您尝试分配大量内存时,也会出现内存错误。这通常是由于创建和销毁了许多不同大小的对象,其中一些对象还活着。如果您的系统存在内存碎片问题,我建议您彻底分析对象是如何创建的,而不是担心是否有成员会影响系统。但是,以下是当您遇到内存碎片时,四种不同场景的详细情况:

  • 实例化
    void use(void)
    {
        ClassA classA;
        classA.doStuff();
    } //classA will be destructed at end of scope 
    
    class User1
    {
    public:
        void use(void)
        {
            classA.doStuff();
        }        
    private:
        ClassA classA;
    };
    
    class User2
    {
    public: 
        void use(void)
        {
            ClassA classA;
            classA.doStuff();
        } 
    };