7

名前を含む本の C++ クラスを書いています。

class Book {
private:
    char* nm;
..........
............
..........
...........
};

std::stringこの課題での使用は許可されていません。したがって、ここでstrdupは、コンストラクターでパラメーター名の値を nm にコピーするために使用しています。

Book::Book(const char *name, int thickness, int weight)
    : nm(NULL)
    , thck(thickness)
    , wght(weight)
{
    if (name)
        nm = strdup(name);
}

を使用せずに同じ結果を達成する代わりに、代わりstrdupにキーワードを使用する方法はありnewますか?

4

5 に答える 5

5

厳密に言えば、このstringクラスは Strings ライブラリの一部です。これははるかに使いやすく、本質的に動的であり、C スタイルの文字列よりもコピー/割り当ての際の心配が少なくなります。

もう 1 つの方法は、手動でコピーすることです。

class Book {
   public:
     Book(const char *name, ...) : nm(0), ... {
           if (!name) throw "invalid parameter";
           nm = new char [ strlen(name) + 1 ];
           strcpy(nm, name);
     }
     ~Book() {
           delete [] nm;
           // ...
     }
     Book(Book const& o) : nm(0), ... {
           if (!name) throw "invalid parameter";
           char *p = new char [ strlen(name) + 1 ];
           if (p) {
               strcpy(p, name);
               delete [] nm;
               nm = p; 
           }
     }
     Book& operator=(Book const& o) {
           if (this != &o) {
              char *p = new char [ strlen(name) + 1 ];
              if (p) {
               strcpy(p, name);
               delete [] nm;
               nm = p; 
              }
           }
           return *this;             
     }
 };

このアプローチの問題点は、メモリを自分で管理し、ビッグ 3 のすべての特別なメンバー関数を自分で実装する必要があることです (そして、例外の安全性を可能な限り確保する必要があります)。

于 2010-03-14T22:39:46.143 に答える
4

実際には答えではありませんが、コメントに収まらない、ひどく修正したものです。彼が行ったほど多くのコードを書くべきではありません。

安全なオブジェクトのコピーは、それほどひどく間違えたくないものですが、実際にはそれを回避する最善の方法は、もちろん、最初に適切なライブラリクラスを使用することです。とは言うものの、単純なCスタイルの文字列は、他のどの文字列よりも優れた例です。

class Book {
    char *nm;
public:
    Book(const char *name) : nm(copystr(name)) { /* don't throw an exception! */ }
    Book(const Book &o) : nm(copystr(o.nm)) { /* Likewise! */ }
    ~Book() { delete[] nm; }
    Book& operator=(const Book &o) {
       // this is called copy-and-swap (CAS). If you absolutely
       // have to write this kind of resource-managing code, then
       // you will need this technique, because it's the best
       // way to provide the strong exception guarantee.
       Book cp = o;
       swap(cp);
       return *this;
    }
    /* or you can do this:
    Book& operator=(Book cp) {
       swap(cp);
       return *this;
    }
    */
    void swap(Book &o) {
       std::swap(this->nm, o.nm);
       // also swap other members
    }
};

char *copystr(const char *name) {
    if (!name) return 0;
    char *newname = new char[strlen(name)+1];
    std::strcpy(newname, name);
    return newname;
}

「例外をスローしないでください!」を参照してください。コンストラクターで警告しますか?そうすると、弦が漏れてしまうからです。クラス内に明示的な解放を必要とする複数のリソースが必要な場合、それは物事が本当に退屈になるときです。正しいことは、文字列を保持するためだけにクラスを作成し、他のリソースを保持するために別のクラスを作成し、Bookクラスに各タイプのメンバーを1人含めることです。そうすれば、コンストラクターの例外について心配する必要はありません。これは、構築されたメンバーは、それを含むクラスのコンストラクター本体がスローされると破棄されるためです。これを数回実行すると、標準ライブラリとTR1を使用することにかなり熱心になります。

通常、労力を節約するために、クラスをコピー不可にすることから始め、コピーコンストラクターとoperator =を実装するのは、必要であることが判明した場合のみです。

class Book {
    char *nm;
public:
    Book(const char *name) : nm(copystr(name)) { }
    ~Book() { delete[] nm; }
private:
    Book(const Book &o);
    Book& operator=(const Book &o);
};

とにかく、strdup大きな謎ではありません。「strdup.c」を検索するだけで、非常によく似た実装がいくつかあります(どちらもGNUからのものです)。同じアプローチは通常、他の文字列処理関数でも機能します。一般に、実装に特別なプラットフォーム依存のメカニズムを必要としないものはすべて、「function_name.c」を探してください。おそらく、その実行方法を説明するGNU実装が見つかります。 、そしてどのようにあなたが似ているが異なることをすることができるか。この場合、あなたは彼らのコードから始めて、への呼び出しmallocとエラー処理を置き換えます。

http://www.koders.com/c/fidF16762E3999BA95A0B5D87AECB0525BA67CEE45A.aspx

http://cvs.frodo.looijaard.name/viewvc/cgi-bin/viewvc.cgi/public/psiconv/compat/strdup.c?revision=1.1.1.1&view=markup

于 2010-03-14T23:29:54.620 に答える
3

はい、代替手段があります。

  • 文字列のサイズを取得する
  • 文字列と同じサイズの配列を作成する
  • 文字列の内容をその配列にコピーします
  • nm割り当てられた配列を指す

または、使用できますstrdup-btw strdupis not part of C++ STL.

于 2010-03-14T22:42:37.343 に答える
0

strlen で malloc してから、strcopy を使用する必要があります。ところで、愚かな宿題。

于 2010-03-14T22:42:40.713 に答える
0
Book::Book(const char *name, int thickness, int weight):nm(NULL), thck(thickness), wght(weight){ 
  if (name) {
     size_t length = strlen(name);
     nm = new char[length + 1];
     memcpy(nm, name, length + 1);
  }
于 2010-03-14T23:20:32.467 に答える