C++ 为什么引用不能在C++;
C++引用有两个属性:C++ 为什么引用不能在C++;,c++,pointers,reference,language-design,C++,Pointers,Reference,Language Design,C++引用有两个属性: 它们总是指向同一个对象 它们不能是0 指针则相反: 它们可以指向不同的对象 它们可以是0 为什么C++中没有“不可空的、可引用的或指针”?我想不出一个很好的理由来解释为什么引用不应该被重新密封 编辑: 这个问题经常出现,因为当我想确保一个“关联”(我在这里避免使用“引用”或“指针”)永远不会无效时,我通常使用引用 我不认为我曾经认为“这个参考总是指同一个对象很好”。如果引用是可重设的,仍然可以得到如下当前行为: int i = 3; int& const j =
- 它们总是指向同一个对象
- 它们不能是0
- 它们可以指向不同的对象
- 它们可以是0
int i = 3;
int& const j = i;
这已经是合法的C++,但是没有意义。 我重申我的问题如下:“引用就是对象”设计背后的基本原理是什么?为什么认为引用总是同一个对象而不是仅当声明为常量时才有用?”
干杯,FelixC++引用有时会在某些编译器中被强制为0(这样做是个坏主意*,它违反了标准*)编辑:根据比我更了解该标准的不同人士的说法,上述代码会产生“未定义的行为”。在GCC和VisualStudio的至少一些版本中,我看到了这样做的预期:等价于将指针设置为NULL(并在访问时导致空指针异常)。C++中的
,经常被称为“引用是对象”。从某种意义上说,这是正确的:尽管在编译源代码时引用被当作指针处理,但引用的目的是表示调用函数时未复制的对象。由于引用不可直接寻址(例如,引用没有地址,&返回对象的地址),因此从语义上讲,重新分配它们是没有意义的。此外,C++已经有指针,它处理重新设置的语义。
我想它与优化有关。p>
当您可以清楚地知道变量的内存意味着什么时,静态优化就容易多了。指针打破了这个条件,可重新设置的引用也会。< P> > C++引用“别名”可能不会那么混乱了。正如其他人提到的,C++中的引用应该是作为变量引用的,而不是作为变量的指针/引用。因此,我想不出一个好的理由,他们应该重新设置
在处理指针时,允许null作为值通常是有意义的(否则,您可能需要一个引用)。如果您特别不允许保留null,您可以编写自己的智能指针类型;) > P> Stroustrup在C++的设计和演化中给出的C++不允许引用引用的原因: 初始化后不可能更改引用引用的内容。也就是说,一旦C++引用被初始化,就不能稍后引用不同的对象;它不能被重新绑定。我过去曾被Algol68引用咬过,
r1=r2
可以通过r1
分配给所引用的对象,或者根据r2
的类型为r1
分配一个新的引用值(重新绑定r1
)。我想避免C++中的这些问题。
因为有时候事情不应该是可重复的。(例如,对单例的引用。) 因为在函数中知道你的参数不能为null是很好的 但最重要的是,因为它允许用户拥有真正的指针,但其行为类似于本地值对象。C++试图引用Stroustrup,使类实例“做为int”。通过vaue传递int很便宜,因为int适合于机器寄存器。类通常比int大,按值传递它们会带来很大的开销 能够传递一个“看起来”像值对象的指针(通常是一个int的大小,或者两个int的大小),允许我们编写更干净的代码,而不需要解引用的“实现细节”。而且,除了运算符重载之外,它还允许我们使用与int类似的语法编写类。特别是,它允许我们使用语法编写模板类,这些语法可以同样应用于基本类(如int)和类(如复数类) 特别是在运算符重载的情况下,有些地方我们应该返回一个对象,但同样,返回指针要便宜得多。再一次,返回引用是我们的“出局” 指针是很难的。也许对你来说不是,对任何意识到指针只是内存地址的值的人来说也不是。但是回想我的CS 101课,他们绊倒了很多学生
char* p = s; *p = *s; *p++ = *s++; i = ++*p;
这可能令人困惑
见鬼,在使用C语言40年后,人们甚至不能同意指针声明是否应该:
char* p;
或
因为这样你就不会有不能为0的可重置类型。除非,你包含了3种类型的引用/指针。这只会使语言复杂化,只会获得很少的收益(那么为什么不添加第4种类型呢?可以为0的不可重置引用?) 一个更好的问题可能是,为什么您希望引用是可重设的?如果它们是可重设的,那么在很多情况下,它们将变得不那么有用。这将使编译器更难进行别名分析 Java或C#中的引用之所以可以重新放置,主要原因似乎是它们执行指针的工作。它们指向对象。它们不是对象的别名 以下情况的影响应该是什么
int i = 42;
int& j = i;
j = 43;
在今天的C++中,使用不可恢复的引用,它是简单的。J是I的别名,我以值43结尾。
如果引用已重新设置
char *p;
int i = 42;
int& j = i;
j = 43;
int i = 42;
int k = 43;
int& j = i;
j = k;
struct null_pointer_exception { ... };
template<typename T>
struct non_null_pointer {
// No default ctor as it could only sensibly produce a NULL pointer
non_null_pointer(T* p) : _p(p) { die_if_null(); }
non_null_pointer(non_null_pointer const& nnp) : _p(nnp._p) {}
non_null_pointer& operator=(T* p) { _p = p; die_if_null(); }
non_null_pointer& operator=(non_null_pointer const& nnp) { _p = nnp._p; }
T& operator*() { return *_p; }
T const& operator*() const { return *_p; }
T* operator->() { return _p; }
// Allow implicit conversion to T* for convenience
operator T*() const { return _p; }
// You also need to implement operators for +, -, +=, -=, ++, --
private:
T* _p;
void die_if_null() const {
if (!_p) { throw null_pointer_exception(); }
}
};
int theInt = 0;
int& refToTheInt = theInt;
int otherInt = 42;
refToTheInt = otherInt;
int firstInt = 1;
int secondInt = 2;
secondInt = firstInt;
firstInt = 3;
assert( firstInt != secondInt );
MyClass & c = *new MyClass();
c = *new MyClass("other")
MyClass * a = new MyClass();
MyClass & b = *new MyClass();
a = new MyClass("other");
b = *new MyClass("another");
struct A{
int y;
int& x;
A():y(0),x(y){}
};
int main(){
A a;
const A& ar=a;
ar.x++;
}
int i = 42;
int k = 43;
int& j = i;
//change i, or change j?
j = k;
int i = 42;
int k = 43;
int& j = i;
//change i, or change j?
//change j!
{
int& j = k;
//do what ever with j's new meaning
}
int a;
int * p = &a;
int a = 10;
int b = 20;
int & r = a;
r = b; // re-set r to b, or set a to 20?
void foo(int & r)
{
int b = 20;
r = b; // re-set r to a? or set a to 20?
}
void main()
{
int a = 10;
foo(a);
}
#include <iostream>
struct Field_a_t
{
int& a_;
Field_a_t(int& a)
: a_(a) {}
Field_a_t& operator=(int& a)
{
// a_.~int(); // do this if you have a non-trivial destructor
new(this)Field_a_t(a);
}
};
struct MyType : Field_a_t
{
char c_;
MyType(int& a, char c)
: Field_a_t(a)
, c_(c) {}
};
int main()
{
int i = 1;
int j = 2;
MyType x(i, 'x');
std::cout << x.a_;
x.a_ = 3;
std::cout << i;
((Field_a_t&)x) = j;
std::cout << x.a_;
x.a_ = 4;
std::cout << j;
}