我正在研究堆栈和堆分配之间的差异,has its own long list of disputes关于何时使用哪个。我的问题与该讨论无关;它是关于测试这两个想法的语义。
考虑以下情况,描述在函数之间传递变量的常用方法:
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;
}
这是我学习如何处理方法之间的变量传递的两种方式。有许多支持和反对here的论据。我读了所有这些。
但是我有一个想法......你知道,我更希望调用者能够轻松地判断一个函数是否概念传值或传递-参考。 (即(func(&amp; var))在我的拙见中,透明度补充了封装的概念。
但是有一个问题。 'new'关键字始终返回指针。从上面的例子可以看出,如果在程序中使用堆栈分配和堆分配变量的混合,很快就会混淆如何通过引用传递它们。
因此,在使用引用类型之后,现在考虑这部分代码:
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;
}
忽略堆分配的变量实例化看起来有多奇怪,有没有人看到这个有什么问题?
它们的功能完全相同。我看到它的方式,选择遵循这种类型的约定允许我自由选择是否在堆栈或堆上分配,同时允许我对我的所有函数使用相同的调用约定,无论它们是否是堆或者堆栈已分配。我个人认为“我会混淆哪些变量分配在堆栈上以及堆上哪些变量”的论证中有任何有效性,但如果您认为我错了,请分享您的意见。
有没有人看到这种方法有什么问题?
答案 0 :(得分:0)
我建议通过引用传递函数。引用表示该对象存在。
当通过指针传递时,接收函数不知道指针是否有效,并且必须测试指针。
通过引用传递是一种更安全,更健壮的风格。
答案 1 :(得分:0)
作为最后的手段通过指针传递。
最佳选择 - 尽可能通过引用传递。引用阻止您传递空指针和悬空指针。它还可以防止你将null作为“无效输入”传递给坏的坏习惯。
还有一些你必须通过const引用传递的地方,比如在任何获取临时对象作为参数的函数中,或者复制构造函数
另外,每个重量超过sizeof(void *)的对象都可以通过引用传递它们 - 参考传递将花费更少的字节复制,因此程序更快。如果需要更改,则将重对象作为引用传递,如果不需要则将其作为const引用。
如果你不能通过引用传递,请尝试通过智能指针传递 - std :: weak_ptr和std :: shared_ptr(你不能传递std :: unique_ptr,或者至少,你不应该)。
在以下情况下通过原始指针传递:
this
如果符合以下情况,则不会通过指针或参考传递:
更多的事情:
new
结果,首先取消引用它:
int& x = *new int(4)
即使你有一个指针作为变量(例如,如果你是imlement链表或单例并使用原始指针),你仍然可以并且应该将它作为参考返回:
T&安培; T ::的getInstance(){ if(!m_Instance){ m_Instance = new T(); } return * m_Instance; }
再次,上面的代码CAN AND应该与智能指针一起使用
答案 2 :(得分:0)
如果你真的想这样做:
然后我认为你可以沿着这些方向做点什么:
auto my_node = make_object<Node>(); // factory hides value/heap creation
然后,您将创建的每个对象都包含在具有指针语义的类中。因此,如果my_node在堆上,它被包装,所以一切都使用my_node-&gt;或* my_node(即使包装器只是将其存储为成员变量)。
由于您现在正在使用包装类型,因此函数可能具有以下签名:
value<Node> my_function( parameter<Node> );
我还没有想过这些课程如何运作的细节,但我正在思考以下几点:
参数只能从reference,value或ptr构造。所以调用者然后指定它想要哪些,并且一些机制在封面处理以正确的形式获取参数。
// in the function with the my_node object
auto ret = my_function( pass_by_reference(my_node) );
我确定在实现中会有一些棘手的问题,但在表面层面上,我认为沿着这些线条会让你重载make_object,因此不同的对象类型会根据需要与堆/堆栈相关联。
你无法使用它作为参考的任何东西 - 你必须处理指针语法,因为它是最低的公分母。但是,您可以保留某些引用或指针(可以为null或反弹)或值(在堆栈上)的语义。
显然,某些地方会出现效率低下的原因,因为通用参数&#39;类型需要能够在3种不同的模式下运行。但是你知道 - 你正试图让语言做一些它没有被设计的东西。然而,C ++的优势在于它的意志,这是一种方式。
也许有人会告诉我为什么以上不起作用。我很高兴听到这个消息,但在粗略的考虑下,我认为可以让它发挥作用。