6

ファイルからバイトをロードし、バイト バッファーとバッファーの長さを含む FileData 構造体を返す関数を作成しました。

バッファーが消費されてスコープ外にスローされるとすぐにバッファーを削除したい。

さまざまなキャスト エラーのため、コンパイルに問題があります。また、バッファがコピーされているのではなく、正しく移動されているかどうかもわかりません。おそらく最大で 16 バイトなので、FileData 構造体自体がコピーされてもかまいません。

一般に、スマート ポインターをクラス/構造体フィールドとしてどのように使用しますか? それはあなたがすることでもありますか?

これは少し漠然とした質問ですが、私はスマート ポインター全般に関して概念的な問題を抱えているため、この例が正しい方向に役立つことを願っています。

ここに私がこれまでに持っているものがあります:

struct FileData
{
    unique_ptr<char[]> buf;
    unsigned int len;
};

FileData LoadFile(string filename)
{
    ifstream str;
    str.open(filename, ios::binary);

    str.seekg(0, ios::end);
    auto len = str.tellg();
    str.seekg(0, ios::beg);

    char* buf = new char[len];

    str.read(buf, len);
    str.close();

    FileData d = { unique_ptr<char[]>(buf), len };

    return d;
}

編集:一部の人々は、この現在のコードで表示されるエラー メッセージに興味があるため、以下に示します。

error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
4

3 に答える 3

6

1つの小さな詳細を除いて、コードは問題ありません。

struct FileData
{
    unique_ptr<char[]> buf;
    <del>unsigned int</del> <ins>streamoff</ins> len;
};

コンパイルされない理由は、コンパイラが特別な移動メンバーの自動生成をまだ実装していないためです。完全にC++11に準拠したコンパイラでは、次のFileDataように動作します。

struct FileData
{
    unique_ptr<char[]> buf;
    streamoff len;

    FileData(FileData&&) = default;
    FileData& operator=(FileData&&) = default;
    FileData(const FileData&) = delete;
    FileData& operator=(const FileData&) = delete;
    ~FileData() = default;
};

デフォルトのmoveコンストラクターは、単に各メンバーをmoveコンストラクトします(デフォルトのmove割り当ての場合も同様です)。

dから戻るLoadFileと、暗黙的にデフォルトの移動コンストラクターにバインドされる暗黙的な移動が発生します。

vector<char>またはstring他の人が示唆しているように使用することもできます。しかし、C ++ 11に関する限り、コードに問題はありません。

ああ、私はそれをそのように微調整するかもしれません:私は自分のリソースをできるだけ早く所有するのが好きです:

FileData LoadFile(string filename)
{
    ifstream str;
    str.open(filename, ios::binary);

    str.seekg(0, ios::end);
    auto len = str.tellg();
    str.seekg(0, ios::beg);

    FileData d = {unique_ptr<char[]>(new char[len]), len};

    str.read(d.buf.get(), d.len);
    str.close();

    return d;
}

FileData移動メンバーを明示的に定義する必要がある場合は、次のようになります。

struct FileData
{
    unique_ptr<char[]> buf;
    streamoff len;

    FileData(FileData&& f)
        : buf(std::move(f.buf)),
          len(f.len)
        {
            f.len = 0;
        }

    FileData& operator=(FileData&& f)
    {
        buf = std::move(f.buf);
        len = f.len;
        f.len = 0;
        return *this;
    }
};

ああ、それは私を別のポイントに導きます。デフォルトの移動メンバーは、ソースで0に設定されていないため、正確には正しくありません。lenこれがバグであるかどうかは、ドキュメントによって異なります。 バッファの長さを反映する~FileData()必要はありません。lenしかし、他のクライアントはそうかもしれません。FileData移動元を信頼できるものではないと定義した場合len、デフォルトの移動メンバーは問題ありません。それ以外の場合は問題ありません。

于 2012-04-13T00:35:27.577 に答える
2

を返すときにコピーされることを気にしない場合は、おそらく a のstd::vector代わりに a を使用します。std:::unique_ptr<char[]>std::vectorFileData

struct FileData 
{ 
    vector<char> buf; 
}; 

FileData LoadFile(string filename) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    FileData d; 
    d.buf.resize(len); 

    str.read(&(d.buf)[0], len); 
    str.close(); 

    return d; 
} 

または、コピーを回避するために、呼び出し元はFileData戻り値の代わりに関数パラメーターとして aを渡すことができます。

struct FileData 
{ 
    vector<char> buf; 
}; 

void LoadFile(string filename, FileData &data) 
{ 
    ifstream str; 
    str.open(filename, ios::binary); 

    str.seekg(0, ios::end); 
    auto len = str.tellg(); 
    str.seekg(0, ios::beg); 

    data.buf.resize(len); 

    str.read(&(data.buf)[0], len); 
    str.close(); 
} 
于 2012-04-13T00:16:50.143 に答える
-1

std::string をバッファとして使用するのはどうですか。必要なすべての動作があります。

  • コピーではなく参照カウント
  • 範囲外になると消える
  • 任意の量の任意のバイトを保持する

文字列の本来の用途ではないため、人々はこれに反対票を投じます。クラスを派生させて(またはラップして)、「バッファ」と呼ぶかもしれません

于 2012-04-13T00:28:34.427 に答える