这是一个非常基本的问题,但是,从C ++专家那里听到它会很好。
在C ++中有两种相似的方法来声明by-reference参数。
1)使用“星号”:
void DoOne(std::wstring* iData);
2)使用“&”“:
void DoTwo(std::wstring& iData);
每种方法的含义是什么? 在任何情况下都有任何问题吗?
奖金#1:在#1和#2中调用方法的正式方法是什么?它们都被称为“按参考”吗?
奖金#2:故意使用std :: wstring。在每种情况下对标准库类有什么影响?
答案 0 :(得分:7)
#1使用指针参数('将指针传递给'),#2使用参考参数('通过引用传递')。它们非常相似,但请注意,在这两种情况下,调用代码看起来不同:
std::wstring s;
DoOne(&s); // pass a pointer to s
DoTwo(s); // pass s by reference
有些人更喜欢#1,使用通过指针传递的约定表明该函数可能会改变s的值(即使任一函数都可以)。其他人(包括我自己)更喜欢#2,因为通过引用传递不允许传递NULL。
传递const
指针或引用时还有另一个重要区别。临时变量只能传递给const引用参数:
void ByConstPointer(const std::wstring&);
void ByConstReference(const std::wstring*);
void test()
{
ByConstPointer(&std::wstring(L"Hello")); // error: cannot take address of temporary
ByConstReference(std::wstring(L"Hello")); // fine
}
答案 1 :(得分:2)
规则编号为1:如果NULL是函数上下文中函数参数的有效值,则将其作为指针传递,否则将其作为参考传递。
基本原理,如果它不能(不应该!)永远为NULL,那么不要让自己完成检查NULL的麻烦。
答案 2 :(得分:1)
在编写示例时,我想出了自己的答案。除了下面以外的任何东西?
每个结果非常相似:对内存中对象的引用最终在方法的范围内。对它们中的任何一个似乎都没有严格的内存要求。该对象可以在堆栈上或堆中。
在堆栈的情况下,每个方法将被调用如下:
{
std::wstring data;
DoOne(&data);
DoTwo(data);
}
然而,当涉及到堆时,第二种方法要求在调用方法之前对象必须存在。如果该对象不存在,则调用者将导致异常,而不是被调用者。
{
std::wstring* pData = new std::wstring();
DoOne(pData);
DoTwo(*pData);
}
在上面,如果发生内存不足的情况且pData结束为NULL,则崩溃将在DoTwo之前发生,但是DoOne会吞下NULL并且可能会在一段时间后崩溃。
答案 3 :(得分:0)
我不会称自己为C ++ gure(除了我的简历),但我会说;除非使用将参数作为指针传递(即函数想要检查null),否则总是使用引用。
这也适用于返回对象的函数,返回指针以某种方式告诉该类的用户它可能为null。
答案 4 :(得分:0)
在DoOne中,可以将iData指定为NULL。如果在调用DoOne后使用它,应用程序将崩溃。
像
这样的东西void DoOne(std::wstring* iData)
{
//Use iData
delete iData;
iData = NULL;
}
和
{
std::wstring* pData = new std::wstring();
DoOne(pData);
pData->someFunction(); //Crash
}
答案 5 :(得分:0)
当你说:
时,你的回答是完全错误的他们每个人的结果都是相当的 类似:对一个对象的引用 记忆最终在方法中 范围。似乎没有严格要求 任何一个的内存要求。
connsider:
void f( int * p1 ) {
int ** p2 = & p1;
}
这里p1有一个明确的“内存要求” - 它必须存在,我必须能够获取其地址。与此对比
void f( int & r ) }
int * p = & r;
}
这里r没有自己的存在,它只是一个参考。我接受它 地址我正在考虑r指的东西的地址。
您对NULL指针的评论也是错误的。取消呈现NULL指针会导致未定义的行为 - 这可能会也可能不会导致崩溃。
答案 6 :(得分:0)
如果你编写一个通过指针获取变量的函数,你很可能必须检查指针是否有效(例如,不是NULL),否则你可能会导致程序崩溃。