析构函数构造函数调用

时间:2012-03-22 20:36:46

标签: c++ constructor

我是初学程序员,我想知道......

我需要为游戏中的对象提供唯一的ID

所以我认为我定义了一个包含全局id的全局类,当我调用一个对象的构造函数时它会递增,而在调用该对象的析构函数时它会递减它。

对于每个构造函数调用都会有相应的析构函数吗?

class id_holder{
private:
    int id_count;

public:
    id_holder() {id_count = 0 ; std::cout<< "unique_id: I'm constructed"<<std::endl;}

    ~id_holder(){std::cout<<"unique_id: I'm destructed"<<std::endl;}

    void increment_id(){id_count ++;};
    void decrement_id(){id_count --;};

    int get_id() {return id_count;};

};

class BaseObject {
protected:
    void increment_id();
    void decrement_id();
public:
    virtual ~BaseObject(){decrement_id();}
    BaseObject();
    BaseObject(V2 pos, ObjectType idobj, double s, Color col);
};

BaseObject::BaseObject(){   
    //stuff
    increment_id();
    unique_id = bObj_id_counter.get_id();
}


BaseObject::BaseObject(V2 pos, ObjectType idobj, double s, Color col){
    //stuff
    increment_id();
    unique_id = bObj_id_counter.get_id(); 
}

void BaseObject::increment_id(){
    bObj_id_counter.increment_id();
}

void BaseObject::decrement_id(){
    bObj_id_counter.decrement_id();
}

方面问题...是否可以比较对象的内存地址(这应该是一个唯一的id),而不是使用id_holder?

5 个答案:

答案 0 :(得分:4)

  

对于每个构造函数调用都会有一个   相应的析构函数?

是的,除非您使用operator new分配对象并且不销毁它们,或者您的应用程序异常终止。

除非您同时使用它,否则您的解决方案应该可以正常运行。如果你这样做,你应该提供对该全局对象的独占访问权,但我不认为是这种情况。

  

是否可以比较内存地址(这应该是唯一的   足够的id)而不是使用id_holder

你可以这样做,每个对象都有一个唯一的内存地址。这是一种肮脏的解决方案,取决于您的目标。

答案 1 :(得分:3)

不,这不一定是真的。在每个表现良好的程序中,每个构造函数调用都有一个析构函数调用。但是,例如,如果使用new构造的对象不是delete d,则不会有析构函数调用。

此外,在您的示例中,您没有实现复制构造函数,这意味着您可能会考虑比构造函数调用更多的析构函数调用。

此外,您也没有实现赋值运算符。如果使用默认对象,则分配给的对象将与分配的对象具有相同的unique_id。 (假设unique_idBaseObject的成员,你没有在你的代码片段中声明。)这样会使你的unique_id非常“独特”。 ; - )

答案 2 :(得分:1)

这通常称为“引用计数”,它具有广泛的用途。是的,这是可能的,但你的工作还不能正常工作。

  1. 如果您想要所有对象的全局唯一标识符,则需要静态保留一个id,然后使用curiously recurring template pattern确保此id仅为全局特定类型。然后,每种类型在构建期间都会获得全局id的副本。
  2. 您需要在copy-constructor中增加计数器
  3. 由于increment_id()类调用decrement_id()id_holder,因此没有理由在BaseObject构造函数/析构函数中再次调用它们。
  4. 如果存在多线程访问,它将无法工作,您需要找到一种原子设置“引用计数”的方法。
  5. 这是一个相对优雅的解决方案,允许您对给定ID的项目执行常量查找等操作。例如:

    警告伪代码(未编译或测试)

    template <class T>
    class counter
    {
       static size_t global_id_;
       size_t id_;
    
    public:
        counter() : id_(global_id_++) {}
        counter(const counter&) : id_(global_id++) {}
        ~counter() {}
    
        counter& operator=(const counter&)
        {
          // left as an exercise for the reader
          // as what to do in this case is highly 
          // dependent upon the application
        }
    };
    
    class counted_object : public counter<counted_object>
    {
       // stuff
    };
    

    现在您可以保存一个存储在向量中的counted_objects查找表,以便快速查找:

    std::vector<counted_object*> lookup;
    counted_object* o416 = lookup[416];
    

答案 3 :(得分:0)

是的,它是,是的,你可以比较地址。唯一的问题是,如果您有内存泄漏,并且对象不会被删除。

每个对象都有一个唯一的地址。即使您创建一个空类或结构,它的大小也不会为零(通过语言设计)。在处理多个线程时,从构造函数传递this引用时要小心,因为您的对象可能没有完全构造。

编辑:你可以利用这个来发现内存泄漏。假设您在程序退出时删除了您创建的每个对象(如清理方法),只需查看是否还有任何对象。

EDIT2:Here's一篇关于C ++中对象计数的非常好的文章

答案 4 :(得分:0)

  1. 是的,每个类都会有一个析构函数,如果你没有提供默认值,编译器会给你一个默认值。看C++ default destructor

    1. 虽然您可以使用内存地址,但不建议使用。特别是,可以得到相当混淆。如果使用共享ptrs等。