4

影響のないコードをすべて削除するのに少し時間を費やしましたが、これが私の問題です。

--- File.h ---

#include <fstream>
#include <string>

template <typename Element>
class DataOutput : public std::basic_ofstream<Element>
{
public:
    DataOutput(const std::string &strPath, bool bAppend, bool bBinary)
    : std::basic_ofstream<Element>(
        strPath.c_str(),
        (bAppend ? ios_base::app : (ios_base::out | ios_base::trunc)) |
(bBinary ? ios_base::binary : 0))
    {
        if (is_open())
            clear();
    }

    ~DataOutput()
    {
        if (is_open())
            close();
    }
};


class File 
{
public:
    File(const std::string &strPath);

    DataOutput<char> *CreateOutput(bool bAppend, bool bBinary);
private:
    std::string m_strPath;
};

--- File.cpp ---

#include <File.h>

File::File(const std::string &strPath)
: m_strPath(strPath)
{
}

DataOutput<char> *File::CreateOutput(bool bAppend, bool bBinary)
{
    return new DataOutput<char>(m_strPath, bAppend, bBinary);
}

--- main.cpp ---

#include <File.h>

void main()
{
    File file("test.txt");

    DataOutput<char> *output(file.CreateOutput(false, false));

    *output << "test"; // Calls wrong overload
    *output << "test"; // Calls right overload!!!

    output->flush();
    delete output;
}

そしてこれは、clオプション/D "WIN32" /D "_UNICODE" /D "UNICODE"を使用してビルドして実行した後の出力ファイルです

--- test.txt ---

00414114test

基本的に何が起こるかというと、最初のoperator<<呼び出しmainはメンバーメソッドにバインドされます

basic_ostream<char>& basic_ostream<char>::operator<<(
    const void *)

一方、2番目のものは(正しく)バインドされています

basic_ostream<char>& __cdecl operator<<(
    basic_ostream<char>&,
    const char *)

したがって、異なる出力が得られます。

次のいずれかを実行した場合、これは発生しません。

  • 列をなしてFile::CreateOutput
  • DataOutput非テンプレートのものに変更しますElement=char
  • 最初の呼び出し*output;の前に追加operator<<

これを望ましくないコンパイラの動作と見なすのは正しいですか?

これについて何か説明はありますか?

ああ、私は現在この簡略化されたコードをテストするためにVC7を使用していますが、VC9とVC8で元のコードを試しましたが、同じことが起こっていました。

どんな助けや手がかりさえもありがたいです

4

3 に答える 3

3

これは、2つの同一のステートメントに対して異なる呼び出しバインディングを生成するため、コンパイラーのバグです(1つのように見えるだけではありません)。

    *output << "test"; // Calls wrong overload
    *output << "test"; // Calls right overload!!!

ただし、コンパイラはこれを行う権利の範囲内にあります。

    void main()

これは、これが有効なC ++プログラムではないことを意味します(void mainCでも許可されておらず、CまたはC ++で有効になったことがありません)。したがって、無効なソースコードをコンパイルした結果を実行しています。その結果は何でもかまいません。

Visual C ++コンパイラが診断しないという事実は、void main単なる別のコンパイラのバグです。

于 2012-03-01T10:14:46.027 に答える
2

コンパイラのバグのようです。最新のVCコンパイラ(現時点ではVC10 Beta2)を試してみて、修正されていない場合は、VCチームにフォローアップしてください(完全な自己完結型リポジトリが必要です)。それが修正された場合、あなたはあなたが見つけた周りの仕事を使ってあなたの人生を続けるべきです。

于 2009-12-28T20:16:37.187 に答える
0

変化する

DataOutput * output(file.CreateOutput(false、false));

DataOutput * output = file.CreateOutput(false、false); そしてそれはうまくいくかもしれません。しかし、これを合理的なlib関数にするために、ポインターではなく実際のオブジェクトを返す必要があった後、クリーンアップする必要はありません。

于 2009-12-28T21:45:27.637 に答える