I'm researching the differences between stack and heap allocation, which has its own long list of disputes on when to use which. My question is not related to that discussion though; it is about the semantics of testing these two ideas.
Consider the following situation describing the usual ways variables are passed between functions:
void passByPtr(Node* n)
{n->value = 1;}
void passByRef(Node& n)
{n.value = 2;}
void passByValue(Node n)
{n.value = 3;}
void indirectionTesting()
{
Node* heapNode = new Node();
Node stackNode= Node();
// Initialize values
heapNode->value = 0, stackNode.value = 0;
cout << heapNode->value << ", "<< stackNode.value << endl;
// Passed ptr by ptr (pass by reference)
passByPtr(heapNode);
passByPtr(&stackNode);
cout << heapNode->value << ", "<< stackNode.value << endl;
// Pass by reference
passByRef(*heapNode);
passByRef(stackNode);
cout << heapNode->value << ", "<< stackNode.value << endl;
// Pass by value
passByValue(*heapNode);
passByValue(stackNode);
cout << heapNode->value << ", "<< stackNode.value << endl;
delete heapNode;
}
int main()
{
indirectionTesting();
/* Output
0, 0
1, 1
2, 2
2, 2 */
return 0;
}
These are the two ways I was taught how to handle variable passing between methods. There are a lot of arguments for and against here. I read all of them.
But I had an idea... you see, I'd prefer for the caller to be able to easily out whether or not a function is conceptually pass-by-value or pass-by-reference. (i.e. (func(&var)) In my humble opinion, the transparency supplements the idea of encapsulation.
But there's a problem. The 'new' keyword always returns a pointer. As you can tell from the above example, if you use a mix of stack-allocated and heap-allocated variables in your program, it can quickly become confusing how to pass them by reference.
So after playing around with reference types, now consider this portion of code:
void passByPtr(Node* n)
{n->value = 1;}
void passByRef(Node& n)
{n.value = 2;}
void passByValue(Node n)
{n.value = 3;}
void indirectionTesting()
{
Node& heapNode = *new Node();
Node stackNode= Node();
// Initialize values
heapNode.value = 0, stackNode.value = 0;
cout << heapNode.value << ", "<< stackNode.value << endl;
// Passed ptr by ptr (pass by reference)
passByPtr(&heapNode);
passByPtr(&stackNode);
cout << heapNode.value << ", "<< stackNode.value << endl;
// Pass by reference
passByRef(heapNode);
passByRef(stackNode);
cout << heapNode.value << ", "<< stackNode.value << endl;
// Pass by value
passByValue(heapNode);
passByValue(stackNode);
cout << heapNode.value << ", "<< stackNode.value << endl;
delete &heapNode;
}
int main()
{
indirectionTesting();
/* Output
0, 0
1, 1
2, 2
2, 2 */
return 0;
}
Ignoring how strange the heap-allocated variable instantiation looks, does anyone see anything wrong with this?
They both function exactly the same. The way I see it, choosing to follow this type of convention allows me to freely choose whether to allocate on the stack or heap whilst allowing me to use the same calling convention for all of my functions, again regardless whether or not they are heap or stack allocated. I don't personally see any validity in the argument that "I will confuse which variables were allocated on the stack and which on the heap," but share your opinion if you think I'm wrong.
Does anyone see anything else wrong with this approach?