1

これに対する答えを探し回っていますが、私の問題に似たものは見つかりませんでした。

コンストラクターでポインターFooを取るクラスがあります。それを と呼びましょう。const char*私のコードでは、パラメーターとして を使用して新しいを作成する必要がありFooます。問題は、文字列が範囲外になると、Foo に渡された値 (またはポインター、これは私が混乱している場所です..) が無効になることです。std::string.data()

文字列が無効になったので、Fooconst char*も無効です。

Foo文字列が範囲外になったときに無効にならないように、文字列のデータの値を渡すにはどうすればよいですか?

4

5 に答える 5

4

文字列のコピーを作成してみませんか? そうすれば、それが消えないことがわかります。const char * がクラスの存続期間中に存在するかどうかわからない場合は、それをコピーする必要があります (または、文字列を参照カウンターでラップするなど、別のことを行います)。

于 2011-02-21T00:17:13.680 に答える
1

次の 2 つのオプションがあります。

  1. (そしてはるかに簡単なオプション)std::stringクラス内に保存するだけです。
  2. で独自のものを割り当てchar*new[]データをコンストラクターstrcpyの newに割り当てます。次に、デストラクタを'schar*に定義する必要もあります。次に、通常の3 つのルールの場合と同様に、コピー コンストラクターとコピー代入演算子を定義して、独自の new (およびコピー代入演算子の場合はold ) を割り当て、fromをコピーする必要があります。オリジナル。間違いを犯してメモリ リークが発生したり、解放されたメモリにアクセスしようとしてランダムにクラッシュしたりするのは非常に簡単です。delete[] Foochar*char*delete[]char*char*Foo

バツ

class Foo {
    char* x;
    Foo(const char* y) {
        copy(y);
    }
    Foo(const Foo &f) {
        copy(f.x);
    }
    Foo& operator= (const Foo f) {
        cleanup();
        copy(f.x);
    }
    ~Foo() {
        cleanup();
    }
    bool copy(const char* y) {
       int len = strlen(y);
       try {
           x = new char[len+1]; //+1 for NULL
       } catch (std::bad_alloc ex) {
           //log failure to allocate memory
           return false;
       }
       return true;
    }
    void cleanup() {
        if (x) {
            delete[] x;
        }
        x = NULL;
    }
};

これは私の頭の上にあるので、何かを省略した可能性は十分にありますが、コメントで指摘してくれるほど親切な人がいると確信しています.

また、shared_ptrfrom Boost を使用すると、オプション #2 の作業が楽になるかもしれませんが、私はあまり経験がなく、小さなプロジェクトで使用するには少し重いかもしれません。

そしてもう一つコメント。必要な NULL 文字を追加するので、実際にはstring.c_str( とは対照的に) も使用する必要があります。string.data

于 2011-02-21T00:44:55.747 に答える
1

Fooコンストラクターの呼び出しスコープを超えて持続させる必要がある場合は、文字列を内部にコピーして保存する必要があります。

于 2011-02-21T00:16:51.410 に答える
0

コピーします。refcount に適した言語では、文字列を「保持」します。しかし、これは C++ です。コピーしないと、ポインターがぶら下がる危険性が高くなります。

class Foo
{
 public:
   Foo(const char*  _data) 
   { 
      mData = new char[strlen(_data) + 1];
      strcpy(mData, _data); 
   }
   Foo& operator=(const Foo& _other) { /* deep copy string */ } 
   Foo(const Foo& _other) { /* deep copy string */ }
   ~Foo() { delete[] mData; }
 private:
   char* mData;
};

また

class Foo
{
 public:
   Foo(const char* _data) : mData(_data) { }
 private:
   std::string mData;
};

また

class Foo
{
 public:
   Foo(const std::string& _data) : mData(_data) { }
 private:
   std::string mData;
};

ご覧のとおり、std::stringオプションの方が簡単です。

于 2011-02-21T00:47:50.693 に答える
0

説明を与えるだけでは、コードで何が問題なのかを解読するのに役立ちません。std::string::data()文字配列の先頭文字へのポインタを返します。渡されたメモリの場所が無効にならない限り、クラス メンバーと渡されたパラメーターの両方が同じ場所を指します。渡されたパラメーターがスコープ外になる (つまり、有効でなくなる) 場合、クラス メンバーはダングリング ポインターになります。その場合は、渡された文字列のコピーを実行することをお勧めします。これはあなたにアイデアを与えるはずです-

#include <iostream>
#include <string>

class Foo
{
    const char* temp;

    public:
    Foo( const char* temp_ ) : temp(temp_) {}
    void check( )
    {
            while( *temp != '\0' ){
                std::cout << *temp ;
                ++temp;
            }
            std::cout << std::endl;
    }
};

int main()
{
    std::string str = "I am a string";

    Foo *obj = new Foo( str.data() );

    obj->check();
    return 0;
}

出力:私は文字列
IdeOneです。お役に立てれば !

于 2011-02-21T00:31:21.820 に答える