I was looking through the documentation on TObject, and I ran across the IsOnHeap() function. I was surprised, because I hadn’t thought it possible for a C++ object to know how it had been allocated. I started playing around with it, and found some rather inconsistent results, as shown below. The left is how the object was constructed, and the right is whether TObject::IsOnHeap
believes it to be on the heap or on the stack.
stack: stack
new: heap
shared_ptr (make_shared): stack
shared_ptr (new): heap
unique_ptr: heap
placement new onto stack: stack
placement new onto heap: stack
On stack, in container: stack
On heap, in container: stack
On stack, in containerobj: stack
On heap, in containerobj: heap
modified stack: heap
Given how unreliable this function is, for what purposes should it be used? Some of the test results differ depending on whether I compile with or without optimization, so it must be relying on undefined behavior.
The testing code is below, and was run on Debian 8, using g++ v4.9.2. This behavior was the same in both root 5.34/36 and 6.06/02.
[code]// Compile with
// g++ -std=c++11 Program.cc -o Program $(root-config --cflags --libs)
#include
#include
#include “TObject.h”
std::string string_result(bool is_on_heap) {
return is_on_heap ? “heap” : “stack”;
}
void funcA() {
char buf[6sizeof(TObject)];
memset(buf, 0x99, 3sizeof(TObject));
}
void funcB() {
TObject obj[3];
std::cout << "modified stack: " << string_result(obj[0].IsOnHeap()) << std::endl;
}
struct Container {
TObject obj;
};
struct ContainerObj : TObject {
TObject obj;
};
int main(){
{
TObject obj;
std::cout << "stack: " << string_result(obj.IsOnHeap()) << std::endl;
}
{
TObject* obj = new TObject;
std::cout << "new: " << string_result(obj->IsOnHeap()) << std::endl;
delete obj;
}
{
auto obj = std::make_shared();
std::cout << "shared_ptr (make_shared): " << string_result(obj->IsOnHeap()) << std::endl;
}
{
auto obj = std::shared_ptr(new TObject);
std::cout << "shared_ptr (new): " << string_result(obj->IsOnHeap()) << std::endl;
}
{
auto obj = std::unique_ptr(new TObject);
std::cout << "unique_ptr: " << string_result(obj->IsOnHeap()) << std::endl;
}
{
char buf[sizeof(TObject)];
TObject* obj = new(buf) TObject;
std::cout << "placement new onto stack: " << string_result(obj->IsOnHeap()) << std::endl;
obj->~TObject();
}
{
void* buf = malloc(sizeof(TObject));
TObject* obj = new(buf) TObject;
std::cout << "placement new onto heap: " << string_result(obj->IsOnHeap()) << std::endl;
obj->~TObject();
free(buf);
}
{
Container c;
std::cout << "On stack, in container: " << string_result(c.obj.IsOnHeap()) << std::endl;
}
{
Container* c = new Container;
std::cout << "On heap, in container: " << string_result(c->obj.IsOnHeap()) << std::endl;
delete c;
}
{
ContainerObj c;
std::cout << "On stack, in containerobj: " << string_result(c.obj.IsOnHeap()) << std::endl;
}
{
ContainerObj* c = new ContainerObj;
std::cout << "On heap, in containerobj: " << string_result(c->obj.IsOnHeap()) << std::endl;
delete c;
}
funcA();
funcB();
}
[/code]