如何在栈或堆上正确初始化对象?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
相关产品推荐
相关产品推荐

