You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在栈或堆上正确初始化对象?C++实现求助

问题:如何让同一对象支持栈或堆上的正确初始化?

tl;dr; 如何在栈或堆上正确初始化对象?

我想要开发一款性能分析工具,既能追踪迭代操作的耗时,也能进行单次测量——这样我可以用同一个对象来测量某个函数(调用N次)的平均耗时,同时也能观察函数在复杂项目中的表现。

我认为这个对象需要既能通过引用初始化(关联全局追踪器时),也能独立在堆上分配(单次使用场景)。我尝试编写了一个最小可复现示例(MRE),请参考以下代码:

struct test{
    
    test(const char *caller, int l )
    :caller(caller),line(l),pntr(nullptr),flag(0)
    {
        std::clog << "instantiated as heap" << std::endl;
        this->make_heap();
    }
    
    test(const test & other)
    {
        std::clog << "copying\t";
        this->caller = other.caller;
        this->line = other.line;
        if( other.is_as_referenece())
        {
            std::clog << "as reference\n";
            this->pntr = other.pntr; // multiple pointers to same variable??
            this->flag = other.flag;
        }
        else
        {
            std::clog << "as heap\n";
            this->pntr = new unsigned(*other.pntr);
            this->flag = other.flag;
        }
    }
    
    test( test && other)
    {
        std::clog << "moving\t";
        this->caller = other.caller;
        this->line = other.line;
        other.caller = "\0"; // moved, thus no caller 
        other.line = 0; // moved, thus no line number
        
        if( other.is_as_referenece())
        {
            std::clog << "as reference\n";
            this->pntr = other.pntr;
            this->flag = other.flag;
            other.unlink_reference();
        }
        else
        {
            std::clog << "as heap\n";
            this->pntr = new unsigned(*other.pntr);
            this->flag = other.flag;
            other.delete_heap();
        }
        
    }
    
    operator bool() { return this->line != 0;} // no line number 0 
    
    test &operator=(const test &other)
    {
        std::clog << "copying\t";
        this->caller = other.caller;
        this->line = other.line;
        if( other.is_as_referenece()) 
        {
            std::clog << "as reference\n";
            this->pntr = other.pntr; // not quite sure about this, 
            this->flag = other.flag;
        }
        else
        {
            std::clog << "as heap\n";
            this->pntr = new unsigned(*other.pntr);
            this->flag = other.flag;
        }
        return *this;
    }
    test &operator=( test && other)
    {
        std::clog << "moving\t";
        this->caller = other.caller;
        this->line = other.line;
        other.caller = "\0";
        other.line = -1;
        
        if( other.is_as_referenece()) // if other is referenced, swap pointers 
        {
            std::clog << "as reference\n";
            this->pntr = other.pntr;
            this->flag = other.flag;
            other.unlink_reference();
        }
        else // if others is heap allocated, make a new heap copy
        {
            std::clog << "as heap\n";
            this->pntr = new unsigned(*other.pntr);
            this->flag = other.flag;
            other.delete_heap();
        }
        return *this;
    }
    test &operator=( unsigned &ref) // normally it generates heap, unless by operator reference is assigned 
    {
        if( this->is_on_heap()) // checks if its heap allocated
        {
            this->delete_heap(); // if is, deletes heap 
        }
        this->link_reference(ref);
        return *this;
    }
    
    ~test()
    {
        std::clog << "deletion proccess" << std::endl;
        if(this->pntr != nullptr) // if not pointing to NULL 
        {
            if(!this->delete_heap()) // try to delete heap, 
            {
                this->unlink_reference(); // if fails, unlink object 
            }
        }    
        
    }
    
    const char *caller; // function name 
    unsigned line; // line number timer is called from 
    
    bool is_on_heap() const // state informers 
    {
        return (flag & 0x1) == 0x1;
    }
    
    bool is_as_referenece() const // state informers 
    {
        return (flag & 0x2) == 0x2;
    }
    
    friend std::ostream &operator<<(std::ostream &, const test &); // for testing purposes 
    
    protected:
        
        bool link_reference(unsigned &value) // links object that is reffered
        {
            if( this->is_on_heap()) {return false;}
            std::cout << "linking reference" << std::endl;
            this->pntr = &value;
            this->set_as_reff();
            return true;
        }
        
        bool unlink_reference() // unlinks object that is reffered
        {
            if( this->is_on_heap()) {return false;}
            std::cout << "unlinking reference" << std::endl;
            this->pntr = nullptr;
            this->clear_as_reff();
            return true;
        }
        
        bool make_heap()  // makes object on heap
        {
            if( this->is_as_referenece() ) { return false;}
            std::cout << "making heap" << std::endl;
            this->pntr = new unsigned(0);
            this->set_as_heap();
            return true;
        }
        
        bool delete_heap() // deletes object if its on heap
        {
            if( this->is_as_referenece() ) {return false;}
            std::cout << "deleting heap" << std::endl;
            delete this->pntr;
            this->pntr = nullptr;
            this->clear_on_heap();
            return true;
        }
        
    private:
        unsigned *pntr = nullptr;   // main data holder.
        uint8_t flag = 0;       // state holder, tracks if object is on heap or reference
        
        // main state changers 
        void set_as_heap()    { flag |= 0x1;}
        void clear_on_heap()    { flag &= 0xfe;}
        void set_as_reff()    { flag |= 0x2;}
        void clear_as_reff()    { flag &= 0xfd;}
            

};

std::ostream &operator<<(std::ostream &os, const test &t)
{
    
    if( t.pntr == nullptr)
    {
        return os << "NOT THERE" << '\t' << t.line << ':' << t.caller;
    }    
    
    if( t.is_as_referenece())
    {
        os << "REFF: " << t.pntr << ' ' << *t.pntr; 
    }
    else
    {
        os << "HEAP: "<< t.pntr << ' ' << *t.pntr; 
    }
    return os << '\t' << t.line << ':' << t.caller;
}

#define TESTER_HEAP test temp = test(__FUNCTION__,__LINE__);

为了获取函数调用信息和行号(基于g++ (C++11.4)、Ubuntu环境),我需要用宏来完成初始化,以准确定位源码位置。目前通过作用域测试、valgrind和gdb验证,代码没有问题:

void test_macro()
{
    unsigned value = 123;    
    
    {
    TESTER_HEAP
    std::cout << temp << std::endl;
    }
    
    std::cout << std::endl;
    
    {
    TESTER_HEAP
    temp = value;
    std::cout << temp << std::endl;
    }
    
    std::cout << std::endl;
    
    {
    TESTER_HEAP;
    test temp2 = temp;
    std::cout << temp << std::endl;    
    std::cout << temp2 << std::endl;
    }
    
    std::cout << std::endl;
    
    {
    TESTER_HEAP;
    test temp2 = (test &&)temp;
    std::cout << temp << std::endl;    
    std::cout << temp2 << std::endl;
    }
}

我尝试过搜索相关内容,但可能因为术语使用不当,没有找到有用的信息。我相信有很多更有经验的开发者做过类似的尝试,希望能得到指引,了解如何实现同一对象支持栈和堆两种分配方式?


内容的提问来源于stack exchange,提问作者Danilo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:58:11