1. ホーム
  2. c++

c++での文字列クラスシミュレーションの実装とbasic_string::_M_construct null not validのエラーの原因について

2022-02-08 12:18:52
<パス

cを学んだ後、c++を学び始めたところ、stringに出会い、その内部実装に興味を持った。cではchar型の配列で文字列を表現し、c++ではstringで文字列を表現する。cでは文字列は' \0' で終わっていると思い、stringオブジェクトに '\0' を初期化しようとしたがコンパイルは通ったが実行がうまくいかなかった。
そこで、'˶'がコンパイルされて通ったから、'A'のような一文字を代入してコンパイラがどうするか見てみようと邪推してみたら、コンパイラから'A ' is not a char* type does not matchと直接言われて唖然としてしまった
と疑問に思い、どうしたらいいのかわからず、上記のエラーをコピーしても納得のいく答えが見つからなかったので、文字列の実装をシミュレートしてみることにしました
そこで私は、この文字列の内部には動的に領域が確保されるはずだと考えました。
そこで、私はクラス

#include <iostream>
#include <cstring>	
#include <cstdlib> //in order to use the exit function and the system function
using namespace std;
class HString
{
    public:
        HString();
        HString(const char *);
        /** print string */
        int StrPrint();
        /* Return the length of the string */
        int GetLength()
        {
            return m_length;
        }
        /* ReSet */
        int ReSet(const char *);
        /* reload=assignment prevent memory leak */
        const HString &operator=(const HString &);
        /* Overload operator = to enable direct assignment with strings */
        const HString &operator=(const char *r_str)
        {
            this->ReSet(r_str);
            return *this;
        }
        virtual ~HString();

    protected:

    private:
        char *m_str; //string dynamically allocated
        int m_length; //the length of the string
        int m_size; //size of current application space
        void InitStr(const char *);//initialize the string
};



以下は、このクラスの実装です。

#include "HString.h"

HString::HString()
{
    m_str = nullptr;
    m_length = 0;
    m_size = 0;
}

void HString::InitStr(const char *initStr)
{
    if(nullptr == initStr)
    {
        cout << "HString::InitStr(const char *): initialization failed by " << __FILE__ << __LINE__ << endl;
        exit(4);
    }
    int len = strlen(initStr);
    m_length = 0;
    m_size = 0;
    m_str = new char[len + 1];
    if(nullptr ! = m_str)
    {
        m_length = len;
        m_size = len + 1;
        memset(m_str, 0, m_size);
        memcpy(m_str, initStr, m_size);
    }
}

HString::HString(const char *initStr)
{
    InitStr(initStr);
}

/** ReSet */
int HString::ReSet(const char *p_str)
{
    if(nullptr == p_str)
    {
        cout << "HString::ReSet :The parameter is incorrect" << endl;
        return 1;
    }
    int len = strlen(p_str);
    if(len < 0)
    {
        cout << "HString::ReSet :get parameter is invailed" << endl;
        return 2;
    }
    if(len < m_size - 1) //if the allocated string is less than the current allocated space length, assign it directly
    {
        memset(m_str, 0, m_size);
        memcpy(m_str, p_str, len + 1);
        m_length = len;
    }
    else // otherwise space reallocation
    {
        if(nullptr == m_str) //if object string has no space
        {
            InitStr(p_str); //initialize
        }
        else
        {
            char *p_temp = new char[len + 1];
            if(nullptr == p_temp)
            {
                cout << "relloc failed!" << endl;
                return 3;
            }
            else
            {
                memset(p_temp, 0, m_size);

                delete m_str;
                m_str = p_temp;
                p_temp = nullptr;
                m_size = len + 1;
                m_length = len;
                memcpy(m_str, p_str, m_size);
            }
        }

    }
    return 0;
}

/* Overload=assignment Prevent memory leaks */
const HString & HString::operator=(const HString &other)
{
	if(this ! = &other) //if passed in other than itself
	{
		if(other.m_size <= this->m_size)
	    {
	        memset(this->m_str, 0, this->m_size);
	        memcpy(this->m_str, other.m_str, other.m_size);
	        this->m_length = other.m_length;
	    }
	    else
	    {
	        if(nullptr ! = this->m_str)
	        {
	            delete this->m_str;
	        }
	        this->m_str = new char[other.m_size];
	        memcpy(this->m_str, other.m_str, other.m_size);
	        this->m_length = other.m_length;
	        this->m_size = other.m_size;
	    }
	}
	   
    return *this;
}



int HString::StrPrint()
{
    if(0 == m_length || nullptr == m_str)
    {
        cout << "NULL" << endl;
        return 1;
    }
    cout << m_str << endl;
    return 0;
}

HString::~HString()
{
    if(nullptr ! = m_str)
    {
        delete m_str;
        m_str = nullptr;
    }
}




私の能力の最大限に文字列をシミュレートする過程で、私は、再割り当てを達成するために、そう、メモリリークと空間の正当な使用しないために、我々は現在のアプリケーション空間のサイズを記録する必要があります文字列の長さの量は、関数strlenを使用する、私はプログラムのデバッグで見つかったstrlenで死亡した問題を発見しました。
そこで、もしポインタが' \0' を指しているならば、そのアドレスは何だろうと考えました。初期オブジェクトで渡したのは char 型のポインタなので、'A' など一文字を渡すと、コンパイラは直接エラーを報告します。型はそうではありませんが '\0' を渡すのは問題ないです。
だから


ようやく原因がわかりました。
strlenにNULLポインタを渡すと、NULLが指す空間にはアクセスできないのでプログラムが死んでしまうので、私のInitStrメソッドは引数を判断していないことに気づき、すぐに上記のコードのように修正しました。
そして、書いたクラスのオブジェクトを'˶'ᴗ'˶に代入した後
次に


コード内に発見

14行目でポップアップ表示されます
その後、私はそれを得た
std::logic_error' のインスタンスをスローした後に呼び出される終了処理
what(): basic_string::_M_construct null not valid

エラーの意味
おめでとうございます~!私の問題はまさにこれで解決です。
このクラスは、ヒープ領域でスペースを適用するときに文字列とは異なるはずですので、したがって、いくつかの効率の問題があるかもしれませんが、私はちょうどエラーを探索したいので、いくつかの機能が実装されていない、軽く兄を噴霧してくださいヾ(≧▽≦)ノ )o *

printf("233を見てくれてありがとう!")。