如果你想编写一个迭代器,你通常会写
T* operator->() const;
我的问题是理解这个" const"用指针和参考。
例如,您可以编写以下结构:
struct A{
int* x;
A(int& x0):x{&x0}{}
int* ptr() const {return x;}
int& ref() const {return *x;}
};
你可以这样使用它:
int x = 10;
const A a{x};
int& r = a.ref();
int* p = a.ptr();
*p = 4;
cout << x << endl; // prints 4
r = 25;
cout << x << endl; // prints 25
但是为什么这个编译并正常工作(至少用g ++和clang)。为什么呢?
正如我所定义的
const A a{x};
这&#34; a&#34;是const。所以当我打电话时
int* p = a.ptr();
我用const对象调用ptr(),因此内部指针A-&gt; x必须是&#34; int * const&#34;。但我正在返回&#34; int *&#34;没有const。为什么这是正确的?
参考会发生什么?如果我使用&#34; const A&#34;调用A :: ref(),那么该函数返回的类型是什么?像&#34; int&amp ;;常量&#34; ??? &lt; ---我想这与&#34; int&amp;&#34;相同。
感谢您的帮助。
答案 0 :(得分:10)
按位常量和逻辑常量之间存在差异。
如果您拥有const A
,则无法修改其int*
成员。但修改成员本身({em> <{em> int
x
指向)和修改成员(int
的值之间存在差异那x
指向)。这些是const
的不同类型。在最简单的情况下:
struct Ptr { int* p; };
int i = 42;
const Ptr ptr{&i};
*ptr.p = 57;
ptr.p
仍然指向i
,没有任何变化,因此const
机制被强制执行。但它不是逻辑const
,因为您仍然通过const
对象更改了某些内容。尽管如此,该语言并没有强制执行。作为图书馆作家,这取决于你。
如果你想传播 const
- ness,你只需提供一个逻辑const
的接口:
int const* ptr() const {return x;}
int const& ref() const {return *x;}
// ^^^^^
现在,用户无法通过const A
按位进行修改(无法改变x
指向的内容)和逻辑上的修改(无法改变该值指出要么)。
答案 1 :(得分:3)
但是为什么这个编译并正常工作(至少用g ++和clang)。为什么呢?
因为程序结构良好并且已经定义了行为。没有违反Const正确性。
我用const对象调用ptr(),因此内部指针A-> x必须是“int * const”。但是我返回一个没有const的“int *”。为什么这是正确的?
因为完成const对象的复制是完全可以的。那些副本不一定是常量。复制对象不会对原始对象进行修改(假设没有用户定义的复制构造函数可以执行愚蠢的操作)。
参考会发生什么?如果我用“const A”调用A :: ref(),这个函数返回的类型是什么?
Date X DATE
0 26-Aug-17 10:11:29 95.617378 NaT
1 26-Aug-17 11:11:29 93.617378 NaT
2 26-Aug-17 12:11:29 91.617378 NaT
3 26-Aug-17 13:11:29 90.000000 NaT
始终返回int& ref()
。就像int&
总是返回int* ptr()
。
类似“int&amp; const”???
没有int*
之类的东西。引用不能有顶级限定符(永远不能重新赋值)。
答案 2 :(得分:2)
在struct A
中,当你创建它的实例const
时,你使指针保持不变,但这不会自动使指向对象保持常量。
声明类似const A a(ref);
的内容基本上等同于调用以下代码:
struct A_const {
int * const x;
A(int& x0):x{&x0}{}
int* ptr() const {return x;}
int& ref() const {return *x;}
};
如果你记得你的指针规则,这意味着x
是一个常量指针,这意味着它不能指向别的东西(它在功能上类似于引用,但可以是null
),但关键的是,它指向的int
不是常数,这意味着没有什么可以阻止你写这样的东西:
int val = 17;
const A a(val);
*(a.val) = 19; //Totally valid, compiles, and behaves as expected!
int val2 = 13;
//a.val = &val2; //Invalid, will invoke compile-time error
这也是std::unique_ptr<int>
和std::unique_ptr<const int>
代表不同对象的原因。
如果希望指向对象不能在const
对象上修改,则需要在代码本身中强制执行。由于函数可以根据源对象是否为const
而重载,这非常简单:
struct A {
int * x;
A(int& x0):x{&x0}{}
int * ptr() {return x;}
int & ref() {return *x;}
int const* ptr() const {return x;}
int const& ref() const {return *x;}
};
int val = 17;
A a(val);
a.ref() = 19;//Okay.
*a.ptr() = 4;//Okay.
const A b(val);
b.ref() = 13;//Compile error
*b.ptr() = 17;//Compile error