[英]Understanding const
如果要編寫迭代器,通常會寫
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};
這個“ a”是常量。 所以當我打電話
int* p = a.ptr();
我正在使用const對象調用ptr(),因此內部指針A-> x必須為“ int * const”。 但是我返回的是沒有const的“ int *”。 為什么這是正確的?
參考會發生什么? 如果我用“ const A”調用A :: ref(),此函數返回的類型是什么? 像“ int&const”之類的東西??? <---我想這與“ int&”相同。
謝謝你的幫助。
按位const和邏輯const之間有區別。
當您擁有const A
,您將無法修改其int*
成員。 但有修改構件本身之間的差( 其 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;}
// ^^^^^
現在,用戶既不能按位(不能更改x
指向的內容)又不能通過邏輯上(也不能更改該指針的值)通過const A
修改。
但是為什么它可以編譯並正確運行(至少在g ++和clang中)。 為什么?
因為程序格式正確,並且定義了行為。 沒有違反常量正確性。
我正在使用const對象調用ptr(),因此內部指針A-> x必須為“ int * const”。 但是我返回的是沒有const的“ int *”。 為什么這是正確的?
因為完全可以復制const對象。 這些副本不必是const。 復制對象不會對原始對象進行修改(假設沒有用戶定義的復制構造函數會執行愚蠢的操作)。
參考會發生什么? 如果我用“ const A”調用A :: ref(),此函數返回的類型是什么?
int& ref()
始終返回int&
。 就像int* ptr()
總是返回int*
。
像“ int&const”之類的東西???
沒有像int& const
這樣的東西。 引用不能具有頂級限定符(永遠不能重新分配它們)。
在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
to不是常數 ,這意味着沒有什么可以阻止您編寫如下內容:
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
來重載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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.