オーバーロードされたクラス型のchar *強制型変換文字を修正するにはどうすればよいですか?

型強制をオーバーロードする際の注意事項

たとえば、クラス型からchar *型への強制を考えてみましょう。char*型への強制は演算子char *()のオーバーロードにすぎないことは誰もが知っていますが、私たちがしばしば気付かないのは、プログラミング後、予期しない現象が発生します(エラー例):

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    operator char*();  
  
    ~Person() = default;  
};  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    return const_cast<char*>(sstr.str().c_str());  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    cout << Person_Obj1 << endl;  
}  

 

出力結果:(すべて文字化け)

 

理由を調べてみましょう:

この理由は、返されるのは一時メモリ空間へのchar *ポインタであるためです。つまり、char *タイプのポインタを返すときです(注:char *強制をオーバーロードすると、クラスタイプTheオブジェクトは、cout出力中に出力するために暗黙的にchar *変数に変換されます)cout出力の前に、次の例に示すように、char *型ポインターが指すメモリー空間が解放されています。

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
char* ShowInf()  
{  
    ostringstream sstr("张三");  
    return const_cast<char*>(sstr.str().c_str()); // 返回指向临时存储空间的char*型指针  
}  
  
int main()  
{  
    cout << ShowInf() << endl;  // 输出之前伴随着ShowInf()函数生命的结束里面的临时变量已经被销毁
}  

 

出力結果:(文字化けしたコードを出力)

 

したがって、オーバーロードされたプログラムに次の改善を加えます。

クラスタイプに新しい変数を追加します。この変数のタイプは、オーバーロードするキャスト演算子の戻り値と一致しています。

char *型のキャスターをオーバーロードしたいので、クラス型にchar *変数を定義して、キャストの結果を格納します。

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
    char* Output;   
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    operator char*();  
  
    ~Person() = default;  
};  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    cout << Person_Obj1 << endl;  
}  

 

出力結果:

 

出力結果は正常であることがわかります。「改善前」と「改善後」の演算子char *()のコードの違いを比較します。

改善前:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    return const_cast<char*>(sstr.str().c_str());  // 返回指向临时存储区域的指针(临时变量其实就是在栈(stack)当中存储的变量,它会随着局部变量堆在函数的释放而被释放掉)
}  

 

 

改善後:

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  // 动态申请内存空间,将数据存在堆区(heap)中
    strcpy(this->Output, sstr.str().c_str());  // 将临时变量的值拷贝至堆区变量当中
    return this->Output;  // 输出堆区变量
}  

 

したがって、将来、必須の変換演算子をオーバーロードして取得した対応する型のデータをこの型に格納し、一時変数を返さないようにする必要があります。一時変数を返す操作は実行できません。

再び改善されたバージョン:要求されたメモリスペースを解放します:

#include <iostream>  
using namespace std;  
#include <sstream>  
#include <string>  
  
class Person  
{  
private:  
    string name;  
    int age;  
    char* Output;   
public:  
    Person() = default;  
    Person(string name, int age);  
    Person(Person& obj);  
  
    explicit operator char*();  
  
    void Cout();  
  
    ~Person();  
};  
  
Person::~Person()  
{  
    if (this->Output != nullptr) // 防止再次被释放引发错误  
    {  
        delete[] this->Output;  
    }  
}  
  
Person::Person(string name, int age)  
{  
    this->name = name;  
    this->age = age;  
}  
  
Person::Person(Person & obj)  
{  
    this->name = obj.name;  
    this->age = obj.age;  
}  
  
Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size() + 1]; // 申请内存空间的时候一定要多预留一个空间  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  
  
void Person::Cout()  
{  
    cout << static_cast<char*>(*this) << endl;  
    delete[] this->Output;  
    this->Output = nullptr;  
}  
  
int main()  
{  
    Person Person_Obj1("张三", 19);  
    Person_Obj1.Cout();  
} 

 

コードでは、次の改善を行いました。

出力関数を作成しました:

void Person::Cout()  
{  
    cout << static_cast<char*>(*this) << endl;  
    delete[] this->Output;  
    this->Output = nullptr;  
}

 

この関数は出力をカスタマイズでき、動的に割り当てられたメモリスペースを再利用することもできます。

Person::~Person()  
{  
    if (this->Output != nullptr) // 防止再次被释放引发错误  
    {  
        delete[] this->Output;  
    }  
} 

 

解放されたメモリが再び解放されないように、必ずこのコードをデストラクタに含めてください。

 explicit operator char*();

​​​​​​​  

オーバーロードされたchar * casterを明示的な型として宣言し、暗黙的な型変換を実行しないようにシステムに指示しました。この操作により、暗黙的な型変換中にメモリスペースを要求するthis-> Outputによって引き起こされるメモリリークを防ぐことができます。

操作中に、次の問題が発生しました。

CRTは、ヒープバッファの終了後にアプリケーションがメモリに書き込んだことを検出しました

この文が示しているのは、解放したメモリスペースがそれ自体の長さを超えていることです。つまり、char型配列の最後の要素は「\ 0」が原因ではなく、空きメモリに終わりはありません。スペースが原因でエラーが発生するため、次の改善を行いました。

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size() + 1]; // 申请内存空间的时候一定要多预留一个空间  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  

 

これのためにもう1つのアプリケーションスペースを予約しました->「\ 0」文字配列の終了マーカーを配置するための出力。改善の場合、明らかにこれを行いませんでした。私の改善コードは次のとおりです。

Person::operator char*()  
{  
    ostringstream sstr;  
    sstr << this->name << "的年龄为" << this->age;  
    this->Output = new char[sstr.str().size()];  
    strcpy(this->Output, sstr.str().c_str());  
    return this->Output;  
}  

 

私たちは質問します:なぜこのコードには何もないのですか?

デストラクタがthis-> Outputが指すメモリ空間を解放しなかったので、なぜですか?

this-> Outputが指すメモリスペースを解放するためのデストラクタ〜Person()を定義しなかったため、システムのデフォルトデストラクタ "〜Person = default"を使用しました。したがって、このコードで動的に割り当てられたメモリスペースは次のように解放されます。プログラム全体が終了します。

また、プログラム全体をリリースするときに「オーバーリリース」エラーが発生しないのはなぜですか。

エラーの理由は、解放したメモリスペースがプログラム内の他のストレージユニットの利益に触れたため、プログラムはエラーを報告しますが、プログラム全体を解放すると、誰が誰の利益を侵害するかという問題はありません。とにかく、すべての利点(メモリ占有)はすべて解放されます。

おすすめ

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