shared_ptr内のowner_beforeの分析(最も理解しやすく、最も包括的)

shared_ptrのowner_beforeの分析

shared_ptrのowner_beforeメンバー関数

shared_ptrのowner_beforeメンバー関数の機能は、「2つのポインターが同じオブジェクトを指しているかどうかを判断する」ことです。

shared_ptrのowner_pointerとstored_pointer

shared_ptrポインターは、異なる属性に従って2つのタイプに分けることができます。

①所有者ポインタがポインタを所有しています:

所有権ポインターは、その名前が示すように、「このポインターは、オブジェクトのメンバーデータではなく、カスタムデータ型オブジェクト全体を指す」ことを意味します。

②格納されたポインタは、内部に格納されたデータへのポインタを指します。

保存されたポインタは、名前でも明確に理解できます。このポインタは、カスタムデータ型オブジェクトの一部を指します。

2つの関係を次の図に示します。

 

「C ++の弱順序」とは何ですか?

①ptrとptr1のポインタは同じタイプですか。

②ptrポインタが指すアドレスがptr1ポインタが指すアドレスよりも小さい。

上記の2つの条件が満たされている場合、「ptr <ptr1」と呼ぶことができます。「違いを残しながら共通点を探る」と考えがちですが、この4つの言葉は「C ++の弱順序」の特徴と一致しているので、弱順序を理解するには「弱順序は何を求めているのか」を理解する必要があります。同じ存在と違い」!

しかし、私たちの疑問が再び浮かび上がります。「同じタイプのポインタ」と呼ばれるために、ptrとptr1はどのような条件を満たすのでしょうか。

まず、shared_ptrには2つの属性があることがわかっているため、ptrとptr1を照合する方法は4つあります。

ptrポインタ属性

ptr1ポインタ属性

Stored_pointer

owner_pointer

owner_pointer

Stored_pointer

owner_pointer

owner_pointer

Stored_pointer

Stored_pointer

抜け道のある各例

⑴ptr1はstored_pointerで、ptrはowner_pointerです。

コード例:

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A  
{  
    int age;  
    double mark;  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<int> ptr1(ptr, &ptr->age);  
    cout << "ptr指针指向的地址为" << ptr.get() << endl;  
    cout << "ptr1指针指向的地址为" << ptr1.get() << endl;  
    cout << "ptr1.owner_before(ptr) = " << ptr1.owner_before(ptr) << endl;  
    cout << "ptr.owner_before(ptr1) = " << ptr.owner_before(ptr1) << endl;  
}  

 

演算結果:

 

プログラムでは、次のように表示されます。

ポインター名

ポインタのターゲット

ptr

タイプAオブジェクト

ptr1

タイプAオブジェクトの年齢メンバーデータ

「弱順序」では、同じオブジェクトへのshared_ptrポインターは、同じタイプのポインターと見なされます。

 

このとき、上記の2つのポインタstored_pointerとowner_pointerは、「弱い順序」で同じタイプのポインタに属しています。

ptrとptr1は同じタイプのポインターであり、ptrポインターは、ptr1ポインターが指すアドレスと等しいため、次のようになります。

 

パラメータの順序に関係なく、最終結果には影響しません。

⑵ptrポインターとptr1ポインターはどちらも、stored_pointer属性を持つshared_ptrポインターです。

コード例:

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A  
{  
    int age;  
    double mark;  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<int> ptr1(ptr, &ptr->age);  
    shared_ptr<double> ptr2(ptr, &ptr->mark);  
    cout << "ptr1指向的地址为" << ptr1.get() << endl;  
    cout << "ptr2指向的地址为" << ptr2.get() << endl;  
    cout << "ptr1.owner_before(ptr2) = " << ptr1.owner_before(ptr2) << endl;  
    cout << "ptr2.owner_before(ptr1) = " << ptr2.owner_before(ptr1) << endl;  
}  

 

演算結果:

 

この時点で、ptr1とptr2が指すアドレスが異なることがわかりますが、パラメーターの位置に関係なく、owner_beforeメンバー関数の戻り値は0のままです。つまり、「異なるデータの2つのstored_pointer属性へのポインター」を意味します。同じカスタムクラスタイプオブジェクトのメンバーshared_ptrポインターは、「弱い順序」で同じタイプのポインターに属しています。ptrとptr1の関係は次のとおりです。

 

⑶ptrとptr1はowner_pointer属性のshared_ptrポインターに属します

コード例:

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A  
{  
    int ageA;  
    double markA;  
};  
  
struct B  
{  
    int ageB;  
    double markB;  
};  
  
struct AB : public A, public B  
{  
  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<B> ptr1 = make_shared<B>();  
    shared_ptr<AB> ptr2 = make_shared<AB>();  
    cout << "ptr指向的地址为" << ptr.get() << endl;  
    cout << "ptr1指向的地址为" << ptr1.get() << endl;  
    cout << "ptr2指向的地址为" << ptr2.get() << endl;  
  
    cout << "ptr(指向class A的对象)与ptr1(指向class B的对象)" << endl;  
    cout << "ptr > ptr1 = " << ((int)ptr.get() > (int)ptr1.get()) << endl;  
    cout << "ptr < ptr1 = " << ((int)ptr.get() < (int)ptr1.get()) << endl;  
    cout << "ptr.owner_before(ptr1)" << ptr.owner_before(ptr1) << endl;  
    cout << "ptr1.owner_before(ptr)" << ptr1.owner_before(ptr) << endl;  
  
    cout << "ptr(指向class A的对象)与ptr2(指向class AB的对象)" << endl;  
    cout << "ptr > ptr2 = " << ((int)ptr.get() > (int)ptr2.get()) << endl;  
    cout << "ptr < ptr2 = " << ((int)ptr.get() < (int)ptr2.get()) << endl;  
    cout << "ptr.owner_before(ptr2)" << ptr.owner_before(ptr2) << endl;  
    cout << "ptr2.owner_before(ptr)" << ptr2.owner_before(ptr) << endl;  
  
    cout << "ptr1(指向class B的对象)与ptr2(指向class AB的对象)" << endl;  
    cout << "ptr1 > ptr2 = " << ((int)ptr1.get() > (int)ptr2.get()) << endl;  
    cout << "ptr1 < ptr2 = " << ((int)ptr1.get() < (int)ptr2.get()) << endl;  
    cout << "ptr1.owner_before(ptr2)" << ptr1.owner_before(ptr2) << endl;  
    cout << "ptr2.owner_before(ptr1)" << ptr2.owner_before(ptr1) << endl;  
}  

 

演算結果:

 

ptr、ptr1、およびptr2のポインターは、以下を指します。

 

上記の継承関係を見ると、「同じタイプ」のポインタペアが次のようになっていることもわかります。

ポインター名

ポインター名

ptr

ptr2

ptr1

ptr2

私たちは、ことがわかりそうな属性owner_pointer 2のshared_ptrのポインタが継承関係を持っており、私たちはへのポインタで、基本クラスのオブジェクトへのポインタを初期化する際に、上記の「同じタイプのポインタのペアが」実際に「継承」されています派生クラスオブジェクト、これら2つのポインタは、「弱い順序で同じタイプのポインタ」に属しています。

最後に、結果を分析すると、「ptrとptr2が指すクラスタイプオブジェクトに継承関係がある場合、ptr.owner_before(ptr2)|| ptr2.owner_before(ptr)== 0」、つまり、ptrおよびptr2。2つのポインタは「弱順序規則」で同じステータスに属します。これはよく「==」と呼ばれますが、現時点で「等しい」は、の2つのポインタptrおよびptr2に対するものです。弱い順序付けルール。

owner_beforeメンバー関数を要約するには

「shared_ptr / weak_ptrのowner_beforeメンバー関数」を使用して、2つのポインターが「同じオブジェクト」を指しているかどうかを判断し、「アドレスへの2つのポインターの順序」を知りたくないので、これを「最初に」行うことができます。 C ++論理演算論理OR演算(||)を使用してから、全体としてNOT(!)演算を実行します ":

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A   
{  
    int age;  
    double mark;  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<int> ptr1(ptr, &ptr->age);  
    cout << "ptr与ptr1指针是否指向同一对象:" << !(ptr.owner_before(ptr1) || ptr1.owner_before(ptr)) << endl;  
}  

 

なぜ論理OR(||)演算を使用するのですか?

ptr.owner_before(ptr1)はtrueを返すため、次の2つの条件を満たす必要があります。

①ptrとptr1の2つのポインタが指すオブジェクトは、「同じタイプのオブジェクト」に属します。

②ptrが指すアドレスは、ptr1が指すアドレスよりも小さくする必要があります。

ptr.owner_before(ptr1)の戻り結果とptr1.owner_before(ptr)の戻り結果を論理的にOR(||)すると、(ptr.owner_before(ptr1)|| ptr1.owner_before(ptr))この全体が返されますvalueは、「ptrおよびptr1ポインターが次々にアドレスを指す」という干渉を排除するため、「(ptr.owner_before(ptr1)|| ptr1.owner_before(ptr))」が0を返す場合、ptrおよびptr1のポインターがptr1は、同じAタイプのオブジェクトを指します。

しかし、この種の外観は少し不快です。「ptrとptr1のポインタが同じタイプのオブジェクトを指している場合はtrueを返したい」のですが、現時点ではfalseを返します。その場合は、逆になります。 2つのポインタが同じタイプのオブジェクトを指しているかどうかを判断するために使用されるコードは、「!(ptr.owner_before(ptr1)|| ptr1.owner_before(ptr))」です。

>、<論理比較記号を使用して「弱い順序での比較操作」を実行してみませんか?

①shared_ptrテンプレートクラスでは、>、<などの論理シンボルの両側にある操作オブジェクトのデータ型は同じである必要があるため、次に例を示します。

上記の例では、ptrはクラスAのオブジェクトを指し、ptr1はクラスABのオブジェクトを指します。現時点では、論理演算子を使用して比較すると、両端のオブジェクトタイプを操作することはできません。クラスAタイプの演算子。クラスABタイプの場合、クラスAとクラスABの2つのクラス間に継承関係がある場合でも、オーバーロードされた論理演算子は結果を比較しません。つまり、役に立ちません。

コード例:

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A   
{  
    int age;  
    int mark;  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<int> ptr1(ptr, &ptr->age);  
    cout << (ptr1 > ptr) << endl; // 因为>逻辑操作符两端操作对象类型不同,因此该行出错  
}  

 

演算結果:

 

②「弱順序ルールでのサイズ比較」はなく、ポインタが指すアドレスに基づいてポインタのサイズ順を判断するだけです。

コード例:

#include <iostream>  
using namespace std;  
#include <memory>  
  
struct A   
{  
    int age;  
    int mark;  
};  
  
int main()  
{  
    shared_ptr<A> ptr = make_shared<A>();  
    shared_ptr<int> ptr1(ptr, &ptr->age), ptr2(ptr, &ptr->mark), ptr3(nullptr);  
    cout << (ptr1 < ptr2) << endl; // 由于ptr1,ptr2指向同一对象,无论如何比较弱序在弱序规则下,ptr1应该与ptr2属于同一类型  
    cout << (ptr1 > ptr2) << endl;  
}  

 

演算結果:

 

明らかに、論理演算子によって実行される関数は「弱い順序でのポインター比較」ではありません。弱い順序で並べ替え規則に従う場合、比較に>または<記号を使用するかどうかに関係なく、最終的な論理結果は0になります。つまり、2つのポインターptrとptr1は弱い順序で同じ位置にあります。 。

おすすめ

転載: blog.csdn.net/weixin_45590473/article/details/113040456