天道酬勤,学无止境

引用和常量引用作为函数参数的区别?(Difference between reference and const reference as function parameter?)

问题

这是一个简单的 C++ 代码片段:

A foo(){
  A a; // create a local A object
  return a;
}

void bar(const A & a_r){

}

bar(foo());

为什么函数 bar 的参数必须是 const 引用,而不仅仅是引用?

Edit1:我知道引用是为了避免复制开销。 和 const 是只读的。 但在这里我必须将它设为 const 引用,否则如果我删除“const”,g++ 会向我抛出错误。

Edit2:我的猜测是 foo() 的返回对象是一个临时对象,并且不允许更改临时对象的值?

回答1

如果没有错误消息,我不确定编译器可能会抱怨什么,但我可以从逻辑上解释原因:

在行中:

bar(foo()); 

foo() 的返回值是一个临时的 A; 它是通过调用 foo() 创建的,然后在 bar() 返回时立即销毁。 执行非常量操作(即更改临时 A 的操作)没有意义,因为对象 A 之后立即被破坏。

再看一点,这是这个问题的虚拟副本:

为什么非常量引用不能绑定到临时对象?

这有一个很好的答案。

回答2

引用必须引用const对象,因为无论如何您都无法利用对它的更改。 比较以下代码片段:

void bar(A&);   
A x = foo();
bar(x);
if (x.member) {...} else {...}

void bar(A const&);   
bar(foo());
if (//x? we don't have any x! We can't branch here!

虽然在第一个示例中,修改对象的能力可能会显着改变后续代码的执行,但在第二个示例中,我们只是没有方法(我们可以参考变量名)来做到这一点。 因此,我们只能使用对 const 的引用,它希望对象不被修改。

回答3

为什么函数 bar 的参数必须是 const 引用,而不仅仅是引用?

bar() 的参数不必是 const 引用。 但是在将对象传递给函数参数时,当对象不会被函数修改时,这是最有效的方式。

  • 将参数设为常量可确保编译器在您尝试修改对象时发出警告。
  • 将参数作为引用传递不会创建对象的副本,因此可以提高效率。
回答4

编译器正在寻找bar(const foo&)因为您正在将const reference to foobar in bar(foo()) - 这是因为您正在传递对临时变量的引用,该变量在bar返回后将不存在

没有任何用例可以通过引用修改foo内部的 foo,因为一旦从bar () 返回,它将不存在。

因此编译器强制执行此操作以防止开发人员将引用传递给临时对象并更新将在方法返回后消失的临时对象的隐藏错误。

回答5

代码 bar(foo()) 将左值传递给 bar()。 只有右值可以有一个指针或引用它。 lvalue 可以有一个 const 引用,因为 const 限制阻止了对不存在的左值的赋值操作。

标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 常量参考和普通参数之间的区别(Difference between const reference and normal parameter)
    问题 void DoWork(int n); void DoWork(const int &n); 有什么不同? 回答1 当您传递较大的struct / class时,区别更加明显。 struct MyData { int a,b,c,d,e,f,g,h; long array[1234]; }; void DoWork(MyData md); void DoWork(const MyData& md); 当您使用use'normal'参数时,您按值传递参数,从而创建传递的参数的副本。 如果使用的是const引用,则按引用传递它,并且不会复制原始数据。 在这两种情况下,都无法从函数内部修改原始数据。 编辑: 在某些情况下,如查尔斯·贝利(Charles Bailey)在回答中指出的那样,原始数据可能会被修改。 回答2 重要的区别是,通过const引用传递时,不会创建新对象。 在函数主体中,参数实际上是传入的对象的别名。 因为引用是const引用,所以函数体无法直接更改该对象的值。 这具有与按值传递相似的属性,在这种情况下,函数主体也不能更改传入的对象的值,在这种情况下,因为参数是副本。 有一些关键的区别。 如果参数是const引用,但是传递给它的对象实际上不是const则在函数调用本身期间可以更改对象的值。 例如 int a; void DoWork(const int &n) {
  • 指针和引用参数之间的区别?(difference between a pointer and reference parameter?)
    问题 这些是一样的吗: int foo(bar* p) { return p->someInt(); } 和 int foo(bar& r) { return r.someInt(); } 忽略空指针电位。 是这两个函数功能相同不管someInt()是虚拟的,或者如果它们传递一bar或子类bar ? 这个切片什么吗? bar& ref = *ptr_to_bar; 回答1 有意在标准中未指定使用指针来实现的C ++引用。 引用更像是变量的“同义词”,而不是指向变量的指针。 当有可能意识到指针在某些情况下会显得过大时,这种语义为编译器打开了一些可能的优化。 还有一些区别: 您不能将NULL分配给引用。 这是一个至关重要的区别,也是您偏爱一个而不是另一个的主要原因。 当您获取指针的地址时,您将获取指针变量的地址。 当您获取引用的地址时,您将获取所引用变量的地址。 您无法重新分配参考。 一旦初始化,它将在整个生命周期中指向同一对象。 回答2 忽略可以用一个而不是另一个来完成的所有语法和可能性,以及在其他答案(针对其他问题)中解释的指针和引用之间的区别……是的,这两个函数在功能上完全相同! 两者都调用该函数,并且均能很好地处理虚函数。 不,您的线不会切开。 它只是将引用直接绑定到指针所指向的对象。 关于为什么要在另一个上使用的一些问题:
  • 返回常量引用和右值引用之间的区别(Difference between returning a const reference and rvalue reference)
    问题 如果我没记错的话,我认为 const 引用和右值引用都可以绑定到右值。 返回前者的函数和返回后者的函数之间有什么实际区别吗? 编辑。 我不能修改前者,但为什么我会对修改右值感兴趣? 是否有意义? 回答1 const左值引用可以绑定到任何东西。 右值引用只能绑定到非const右值。 non-const lvalue const lvalue non-const rvalue const rvalue const T& yes yes yes yes T&& no no yes no 如您所见,它们非常不同。 此外,如果函数调用返回左值引用,则该表达式是左值,但如果函数调用返回对对象的右值引用,则该表达式是 xvalue。 如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值,如果结果类型是对对象类型的右值引用,则是 xvalue,否则是 prvalue。 至于何时需要修改右值——这正是移动语义的全部内容。 考虑以下函数调用: void func(std::string); func(std::string("Hello")); 表达式std::string("Hello")是一个创建临时对象的右值。 使用此右值初始化std::string参数时,它将选择接受右值引用的构造函数-移动构造函数。 这个构造函数然后从右值中窃取东西,这通常比做一个完整的复制要快得多。
  • 特质和政策有什么区别?(What is the difference between a trait and a policy?)
    问题 我有一个类,我正在尝试配置其行为。 template<int ModeT, bool IsAsync, bool IsReentrant> ServerTraits; 然后我有我的服务器对象本身: template<typename TraitsT> class Server {…}; 我的问题是我上面的用法是我的命名错误吗? 我的模板化参数实际上是策略而不是特征吗? 什么时候模板化参数是特征还是策略? 回答1 政策 策略是将行为注入父类的类(或类模板),通常是通过继承。 通过将父接口分解为正交(独立)维度,策略类构成了更复杂接口的构建块。 一种常见的模式是将策略作为用户可定义的模板(或模板模板)参数提供,并带有库提供的默认值。 标准库中的一个例子是分配器,它们是所有 STL 容器的策略模板参数 template<class T, class Allocator = std::allocator<T>> class vector; 在这里, Allocator模板参数(它本身也是一个类模板!)将内存分配和释放策略注入到父类std::vector 。 如果用户不提供分配器,则使用默认的std::allocator<T> 。 与基于模板的多态性一样,策略类的接口要求是隐式和语义(基于有效表达式)而不是显式和句法(基于虚拟成员函数的定义)。 请注意,最近的无序关联容器具有多个策略。
  • const int *,const int * const和int const *有什么区别?(What is the difference between const int*, const int * const, and int const *?)
    问题 我总是弄乱了如何正确使用const int* , const int * const和int const * 。 是否有一组规则定义您可以做什么和不能做什么? 我想知道在分配,传递给函数等方面所有需要做的事情和所有不应该做的事情。 回答1 向后读取(在顺时针/螺旋规则的驱动下): int* -指向int的指针 int const * -指向const int的指针 int * const指向int的const指针 int const * const指向const int的const指针 现在,第一个const可以位于类型的任一侧,因此: const int * == int const * const int * const == int const * const 如果您想发疯,可以执行以下操作: int ** -指向int的指针 int ** const指向int的指针的const指针 int * const * -指向const的指针指向int的指针 int const ** -指向const int的指针 int * const * const指向int * const * const的const指针的const指针 ... 并且确保我们对const的含义很清楚: int a = 5, b = 10, c = 15; const int* foo; //
  • 指针和引用之间的区别(作为线程参数)(Difference between pointer and reference as thread parameter)
    问题 这是示例: #include<iostream> #include<thread> using namespace std; void f1(double& ret) { ret=5.; } void f2(double* ret) { *ret=5.; } int main() { double ret=0.; thread t1(f1, ret); t1.join(); cout << "ret=" << ret << endl; thread t2(f2, &ret); t2.join(); cout << "ret=" << ret << endl; } 输出为: ret=0 ret=5 使用gcc 4.5.2编译,带有和不带有-O2标志。 这是预期的行为吗? 该程序数据竞赛免费吗? 谢谢 回答1 std::thread的构造函数推导参数类型并按值存储它们的副本。 这是必需的,以确保参数对象的生存期至少与线程的生存期相同。 C ++模板函数参数类型推导机制从类型T&的参数推导类型T 复制std::thread所有参数,然后将其传递给线程函数,以便f1()和f2()始终使用该副本。 如果您坚持使用引用,请使用boost::ref()或std::ref()来包装参数: thread t1(f1, boost::ref(ret)); 或者,如果您更喜欢简单性,请传递一个指针
  • C#中const和readonly有什么区别?(What is the difference between const and readonly in C#?)
    问题 C#中const和readonly什么区别? 您什么时候可以使用另一个? 回答1 除了表观上的区别 必须在定义const时声明值readonly值可以动态计算,但需要在构造函数退出之前分配。 'const'是隐式static 。 您使用ClassName.ConstantName表示法来访问它们。 有细微的差别。 考虑在AssemblyA定义的类。 public class Const_V_Readonly { public const int I_CONST_VALUE = 2; public readonly int I_RO_VALUE; public Const_V_Readonly() { I_RO_VALUE = 3; } } AssemblyB引用AssemblyA并在代码中使用这些值。 编译后, 在const值的情况下,就像是一个查找替换,值2被“烘焙”到AssemblyB的IL中。 这意味着,如果明天我将在将来将I_CONST_VALUE更新为20。 在我重新编译之前, AssemblyB仍将有2个。 在readonly值的情况下,它类似于对存储位置的ref 。 该值未烘焙到AssemblyB的IL中。 这意味着,如果内存位置已更新, AssemblyB将获得新值,而无需重新编译。 因此,如果I_RO_VALUE更新为30,则只需要构建AssemblyA 。
  • Swift Closures 和 First-Class Functions 有什么区别?(Swift any difference between Closures and First-Class Functions?)
    问题 在 Swift 文档中,Apple 是这样说的: 闭包是独立的功能块,可以在您的代码中传递和使用。 Swift 中的闭包类似于 C 和 Objective-C 中的块以及其他编程语言中的 lambda。 我认为这是一等函数的定义 他们还这样说: 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。 这称为关闭这些常量和变量。 Swift 为您处理所有捕获的内存管理。 我认为这是闭包的定义,而另一个定义是用于一流的函数,但 Apple 似乎将它们放在一起并称之为闭包。 我是不是误解了什么? 还是 Apple 调用闭包和一流的函数闭包? 我已经编写了这个示例代码,只是想知道我在书面评论中是否正确? // 'a' takes a first class function, which makes 'a' a higher order function func a(ch: () -> Void){ print("Something") ch() // 'ch' is a first class function print("Ended") } func closureFunc(){ var num = 2 a({ // access to 'num' is possible by closures num = num*2 print(num) }) }
  • C++ Lambdas:“可变”和按引用捕获之间的区别(C++ Lambdas: Difference between “mutable” and capture-by-reference)
    问题 在 C++ 中,您可以像这样声明 lambdas: int x = 5; auto a = [=]() mutable { ++x; std::cout << x << '\n'; }; auto b = [&]() { ++x; std::cout << x << '\n'; }; 两者都让我修改x ,那么有什么区别呢? 回答1 怎么了 第一个只会修改它自己的x副本,而保持外部x不变。 第二个将修改外部x 。 尝试每个后添加打印语句: a(); std::cout << x << "----\n"; b(); std::cout << x << '\n'; 预计打印: 6 5 ---- 6 6 为什么 考虑 lambda 可能会有所帮助 [...] 表达式提供了一种创建简单函数对象的简洁方法 (参见标准的 [expr.prim.lambda]) 他们有 [...] 公共内联函数调用运算符 [...] 它被声明为一个const成员函数,但仅 [...] 当且仅当 lambda 表达式的参数声明子句后面没有mutable 你可以认为好像 int x = 5; auto a = [=]() mutable { ++x; std::cout << x << '\n'; }; ==> int x = 5; class __lambda_a { int x; public: _
  • 在 PHP 中,将变量声明为函数内部的全局变量或将变量作为参数传递给函数有什么区别?(In PHP, what is the difference between declaring a variable as global inside function, or passing the variable as an argument to the function?)
    问题 将函数中的变量声明为global或public/private VS 将其作为参数传递给函数有什么区别? 其他相关混淆 我最近让自己很头疼,试图将 aa 数组变量作为global变量传递到函数中并在内部对其进行编辑并希望将其返回更改,我花了几个小时才弄清楚我需要将它作为一个函数传递给函数引用参数,如functionCall(&$arrayVar); 次要问题:但我仍然想知道,为什么将变量作为global变量传入然后编辑它并用return其吐出或者只是通过执行诸如连接到变量数组之类的操作不起作用? 我最近遇到的另一个例子是为 PHPMailer 创建一个函数,我向它传递几个参数,如电子邮件地址和消息正文,但我还需要向它传递身份验证字符串,如 API 密钥等。在这里,每个时间我称之为: 我不想每次调用 PHMailer 函数时都必须向它传递身份验证凭据(例如,在几个阶段之一通过电子邮件发送错误消息) 但我确实想每次调用它时都传递唯一的参数 所以我想最好的方法是这样的: function phpMailer( $mail_to = "to@email.com", $mail_from = "a@b.com" ) { global $authCredentials; } // And of course, when I call phpMailer, I call it like
  • “文本”和新字符串(“文本”)之间有什么区别?(What is the difference between “text” and new String(“text”)?)
    问题 以下两个语句之间有什么区别? String s = "text"; String s = new String("text"); 回答1 new String("text"); 显式创建String对象的新的且具有参照性的不同实例; String s = "text"; 如果有一个实例,可以从字符串常量池中重用一个实例。 您很少会想使用new String(anotherString)构造函数。 从API: String(String original):初始化一个新创建的String对象,以便它表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。 除非需要显式的原始副本,否则不需要使用此构造函数,因为字符串是不可变的。 相关问题 Java字符串:“字符串s =新字符串(“傻”));” 字符串是Java中的对象,那么为什么不使用'new'来创建它们呢? 参照区别是什么意思 检查以下代码段: String s1 = "foobar"; String s2 = "foobar"; System.out.println(s1 == s2); // true s2 = new String("foobar"); System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); //
  • C和C ++中的“按引用传递”之间到底有什么区别?(What exactly is the difference between “pass by reference” in C and in C++?)
    问题 C和C ++开发人员都使用短语“通过引用传递”,但是它们似乎用来表示不同的含义。 每种语言中这个模棱两可的词组之间到底有什么区别? 回答1 有些问题已经解决了按引用传递和按值传递之间的区别。 从本质上讲,按值将参数传递给函数意味着函数将拥有其自己的参数副本-将其值复制。 修改该副本不会修改原始对象。 然而,通过引用传递时,在该函数内的参数是指在通过了相同的对象-的任何改变内部的功能可以看到外面。 不幸的是,有两种使用短语“按值传递”和“按引用传递”的方法,这可能会引起混淆。 我认为,这部分是为什么新C ++程序员难以采用指针和引用的原因,尤其是当它们来自C的背景时。 C 在C语言中,技术意义上的一切都是通过价值传递的。 也就是说,无论您将什么作为函数的参数,它都将被复制到该函数中。 例如,调用一个函数void foo(int)与foo(x)副本的值x作为参数foo 。 可以在一个简单的示例中看到: void foo(int param) { param++; } int main() { int x = 5; foo(x); printf("%d\n",x); // x == 5 } x的值被复制到foo并且该副本递增。 main的x继续具有其原始值。 如您所知,对象可以是指针类型。 例如, int* p定义p作为指针以一个int 。 重要的是要注意,以下代码引入了两个对象:
  • std :: reference_wrapper和简单指针之间的区别?(Difference between std::reference_wrapper and simple pointer?)
    问题 为什么需要std :: reference_wrapper? 应该在哪里使用? 它与简单的指针有何不同? 与简单指针相比,它的性能如何? 回答1 std::reference_wrapper与模板结合使用非常有用。 它通过存储指向对象的指针来包装对象,从而允许在模仿其通常语义的同时进行重新分配和复制。 它还指示某些库模板存储引用而不是对象。 考虑STL中复制函子的算法:您可以通过简单地传递引用函子而不是函子本身的引用包装器来避免该复制: unsigned arr[10]; std::mt19937 myEngine; std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state 之所以有效,是因为... … reference_wrapper的重载operator(),因此可以像它们所引用的函数对象一样对其进行调用: std::ref(myEngine)() // Valid expression, modifies myEngines state …(不像普通引用一样),复制(和分配) reference_wrappers只是分配指针对象。 int i, j; auto r = std::ref(i); // r refers to i r = std::ref(j); //
  • 通用引用和转发引用之间有区别吗?(Is there a difference between universal references and forwarding references?)
    问题 该函数的参数将绑定到右值引用: void f(int && i); 但是,此函数的参数将绑定到右值或左值引用: template <typename T> void f(T && t); 我经常听到这被称为通用参考。 我也听说过它被称为转发参考。 他们是同一意思吗? 如果函数主体调用std::forward它仅仅是转发参考吗? 回答1 他们是同一意思吗? 通用引用是斯科特·迈耶斯(Scott Meyers)创造的一个术语,用于描述对cv不合格模板参数采用右值引用的概念,然后可以将其推导出为值或左值引用。 当时,C ++标准对此没有一个特殊的术语,这是C ++ 11中的一个疏忽,因此很难讲授。 N4164纠正了这种疏忽,在[temp.deduct]中添加了以下定义: 转发引用是对cv不合格模板参数的右值引用。 如果P是转发引用,并且参数是左值,则使用类型“对A的左值引用”代替A进行类型推导。 因此,两者含义相同,当前的C ++标准术语是转发参考。 本文本身阐明了为什么“转发参考”比“通用参考”更好的术语。 如果函数主体调用std::forward它仅仅是转发参考吗? 不会,您对转发引用所做的操作与名称无关。 概念转发参考仅涉及如何在以下情况中推导类型T : template <class T> void foo(T&& ); // <== 不需要随后转发。 回答2 不幸的是
  • std :: move和std :: forward之间有什么区别(What's the difference between std::move and std::forward)
    问题 我在这里看到了这一点:Move构造函数调用基类Move构造函数 有人可以解释: std :: move和std :: forward之间的区别,最好带有一些代码示例? 如何轻松思考,以及何时使用 回答1 std::move接受一个对象,并允许您将其视为临时对象(右值)。 尽管这不是语义要求,但是通常,接受对右值的引用的函数会使它无效。 当您看到std::move ,表明该对象的值此后不应再使用,但是您仍然可以分配一个新值并继续使用它。 std::forward有一个用例:将模板化的函数参数(在函数内部)强制转换为调用者用来传递值的值类别(左值或右值)。 这允许将rvalue参数作为rvalue传递,并将lvalues作为lvalues传递,这种方案称为“完美转发”。 为了显示: void overloaded( int const &arg ) { std::cout << "by lvalue\n"; } void overloaded( int && arg ) { std::cout << "by rvalue\n"; } template< typename t > /* "t &&" with "t" being template param is special, and adjusts "t" to be (for example) "int &" or non
  • “const ref”和“in”之间的区别?(Difference between 'const ref' and 'in'?)
    问题 我试图了解const ref和in之间的区别,特别是在性能方面。 我知道in相当于const scope ,但是the scope storage class means that references in the parameter cannot be escaped (eg assigned to a global variable). 意思? 欢迎使用示例代码。 实现函数时如何在const ref和in之间做出决定? 我知道ref对象不会被复制,因为它是一个引用,但是in也是如此? 回答1 1) scope参数存储类意味着您不允许对参数的引用进行转义。 例子: Object glob; struct S { Object o; void foo(scope Object o) { this.o = o; // Not allowed! 'o' must not be escaped glob = o; // ditto } } 请注意,DMD 不太擅长检测这一点。 上面的示例当前可以编译,但不被允许。 scope对委托参数最有用: void foo(scope void delegate() dg) { /* use dg */ } void main() { int i; foo({ ++i; }); } 在上面的例子中,不需要为匿名函数分配闭包,即使它有一个
  • swift中的let和var有什么区别?(What is the difference between `let` and `var` in swift?)
    问题 Apple的Swift语言中let和var什么区别? 以我的理解,它是一种编译语言,但它不会在编译时检查类型。 这让我感到困惑。 编译器如何知道类型错误? 如果编译器不检查类型,那么生产环境是否存在问题? 回答1 let关键字定义一个常量: let theAnswer = 42 theAnswer将无法更改。 这就是为什么不能使用let编写任何weak原因。 它们需要在运行时进行更改,而您必须使用var来代替。 var定义一个普通变量。 有趣的是: 常量的值不需要在编译时就知道,但是您必须精确地分配一次值。 另一个奇怪的功能: 您几乎可以将任何喜欢的字符用于常量和变量名称,包括Unicode字符: let 🐶🐮 = "dogcow" 摘录自:苹果公司“ The Swift Programming Language”。 iBooks。 https://itunes.apple.com/WebObjects/MZStore.woa/wa/viewBook?id=881256329 编辑 因为评论要求在答案中添加其他事实,所以将其转换为社区Wiki答案。 随意编辑答案以使其更好。 回答2 根据《 The Swift Programming Language Book》 与C一样,Swift使用变量来存储和通过标识名称引用值。 Swift还广泛使用了无法更改其值的变量。
  • 按引用调用和按值调用之间的区别[重复](Difference between call by reference and call by value [duplicate])
    问题 这个问题已经在这里有了答案: 11年前关闭。 可能重复: 值参数和参考参数之间的区别? 按引用调用和按值调用有什么区别? 回答1 在C中,没有引用调用。 您能获得的最接近的地址是地址,然后传递该地址的副本(按值-参见下文)。 在C ++中,按引用调用会将引用传递给对象(原始对象的别名)。 通常不能保证将其作为对象的地址来实现。 按值调用意味着获取某种值,并将该值的副本传递给函数。 基本区别在于,当您按值传递参数时,该函数仅接收原始对象的副本,因此它不会做任何事情来影响原始对象。 通过引用传递,它可以获得对原始对象的引用,因此它可以访问原始对象,而不是其副本-除非它是const引用,否则它可以修改原始对象(例如)。 回答2 简而言之,按引用调用是函数可以修改其参数的时间: def f(x): x := x + 1 print(x) x := 1 f(x) /* Now, x is 2 */ print(x) 在“按引用呼叫”,上面将打印2两次。 按值调用是指函数收到传递给它的参数的副本时,因此调用者看不到任何修改。 使用上面定义的f(x) ,按值调用将是: x := 1 f(x) /* x is 1 in the caller */ print(x) 在上面的f(x)内部,print调用将打印2 ,但是仅修改f()获得的x的副本,因此在调用方中, x仍为1,第二个print(
  • const之间的区别指针和参考?(Difference between const. pointer and reference?)
    问题 常量指针和引用之间有什么区别? 顾名思义,常量指针无法再次绑定。 参考文献也是如此。 我想知道哪种方案比另一方案更可取。 他们的C ++标准及其实现有何不同? 干杯 回答1 有3种类型的const指针: //Data that p points to cannot be changed from p const char* p = szBuffer; //p cannot point to something different. char* const p = szBuffer; //Both of the above restrictions apply on p const char* const p = szBuffer; 上面的方法2与参考最相似。 引用与以上所有3种const指针之间都存在关键区别: 常量指针可以为NULL。 引用没有自己的地址,而指针却有。 引用的地址是实际对象的地址。 指针具有自己的地址,并且将其指向的值的地址作为其值。 有关引用和指针之间的更多区别,请参见此处的答案。 回答2 我假设您的意思是一个const值的指针(例如int * const ptr),而不是指向const的指针(例如int const * ptr)。 不初始化引用是编译错误(避免了未初始化指针的问题) 指针也可以指向数组,也可以为NULL,其中引用始终恰好指向一个对象。
  • 按值传递与按引用传递(两者之间内存空间分配的差异)(Pass by value vs Pass by reference(difference in space allocation of memory between the two))
    问题 在我们使用按引用传递的 C++ 中,我们引用从参数传递给函数参数的任何地址,这本质上是一个指针,对吗? 因此,虽然它们本质上是相同的东西,别名和所有,但指针是否也需要内存空间? 因此,我们在参数函数中拥有的任何内容都不应该让我们调用 B 指向所传递参数的内存位置,让我们调用 A,这反过来又是我们值的内存位置(因为 A 传递了我们值的内存位置作为论点)? 在我们使用按值传递的java中,我们复制了我们传递的任何地址(例如对对象的引用)。 所以最后我并没有真正看到按值传递和按引用传递之间的区别。 按值传递为原始传递的参数分配内存空间,指向该值并按引用传递的副本将我们值的内存位置作为参数传递给我们的参数(在内存中分配空间的指针)函数用于指向值。 回答1 在我们使用按引用传递的 C++ 中,我们引用从参数传递给函数参数的任何地址,这本质上是一个指针,对吗? 不是。引用是现有变量的别名(即替代名称)。 但是在汇编级别,您的实现可能会将引用变量的地址放在地址寄存器(或类似的东西)中以供被调用函数使用(如果这是您的意思)。 但是为了简化起见,您可以将其视为自动取消引用的指针(这是我刚开始时所做的)。 但是当您进入语言时,引用实际上与指针有根本的不同。 因此,虽然它们本质上是相同的东西,别名和所有,但指针是否也需要内存空间? C++ 级别的指针需要空间(因为它是可寻址的)。