1

私はすでにこの問題の回避策を見つけましたが、私が見ている問題を引き起こすために実際に何が起こっているのか誰かが知っているかどうか疑問に思っていました。私の推測では、それは文字列の可変性と関係があると思いますが、コピーコンストラクターではCStringオブジェクトがそれを説明していると思いました。

次のコードにより、mFileNameが上書きされます。

class File {
public: 
 ...
 CString GetFilename() {return mFileName;}
private:
 CString mFileName;
};

class FileContainer {
private: File* mFile;
public:
 FileContainer() {
  mFile = new File("C:\temp.txt");
}
 GetFilename(CString& fileName) {
  fileName = mFile->GetFileName();
 }
}

void UpdateText() {
FileContainer fileCnt;
CString filePath(L"");
this->fileCnt.GetFilename(filePath);
...
::DrawText(hDC, filePath, -1, &destRect, DT_PATH_ELLIPSIS | DT_MODIFYSTRING | DT_CALCRECT);
}

何が起こるかというと、UpdateTextが最初に呼び出されたときに、GetFilenameはC:\temp.txtを返します。バウンディングレクが最初の呼び出しでテキストを「...\temp.txt」に切り捨てたと仮定すると、「...\temp.txt」はUpdateTextへの2回目の呼び出しでGetFilenameから返されるものです。

さらに厄介なのは、これによってmFileNameが変更されなかったことです。

void UpdateText() {
FileContainer fileCnt;
CString filePath(L"");
this->fileCnt->GetFilename(filePath);
filePath = L"TEST";
}

GetFilenameは常にC:\temp.txtを返しました。したがって、DrawText関数はどういうわけか元のCStringを見つけて、それを変更しているように見えます。しかし、どのように?

更新: mFileNameが上書きされる原因となる別の奇妙なコードチャンクをスローすると思いました:

class File {
public: 
 ...
 CString GetFilename() {return CString(mFileName);}
private:
 CString mFileName;
};

新しいオブジェクトを作成し、その新しいオブジェクトを返す必要があるようです。それでも、どういうわけか、DrawTextはまだmFileNameを上書きします。

コードを次のように変更しても、問題はありません。

class File {
public: 
 ...
 CString GetFilename() {return CString(mFileName.GetBuffer());}
private:
 CString mFileName;
};

問題を解決しているように見える唯一のことは、回避策で示した方法で新しいCStringを構築することです。DT_MODIFYSTRINGオプションを渡すと、DrawTextは何をしますか?

4

2 に答える 2

4

まず、CStringは2つの方法で生の文字列ポインタとして使用できることに注意してください。

  1. operator LPCSTR-決して変更してはならないポインタを提供します。
  2. GetBuffer-特に文字列を変更する目的でメモリへのポインタを提供します。

これで、DrawTextはLPCSTRを受け入れるように宣言されました。したがって、コードのようにCStringオブジェクトを直接渡すと、CStringオブジェクトは暗黙的に使用operator LPCSTRして、関数に必要なもの、つまり定数文字列ポインターを提供します。

ただし、DT_MODIFYSTRINGは、DrawTextが指定された文字列を変更できることを示しています。したがって、内部的には、DrawTextはポインタの定数を破棄し、とにかく文字列を変更する必要があります。

この組み合わせは悪いことです。しかし、欠点は主に、独自の宣言に違反しているDrawTextの実装にあります。

これが他のCStringオブジェクトを変更する理由について:明らかに、CStringオブジェクトがコピーされると、何かがCStringメンバー関数を介して文字列を変更しようとするまで、内部文字列メモリのコピーを遅らせます。ただし、それが発生するまで、operator LPCSTR各CStringオブジェクトのは同じ共有内部メモリを指します。これを使用するコードがconst-correctnessのルールに従っている限り、これは通常は問題ありません。ただし、すでに見てきたように、DT_MODIFYSTRINGを使用したDrawTextはルールに従って再生されていません。したがって、複数のCStringオブジェクトによって共有されているメモリを上書きしています。

したがって、この問題を修正するには、実際に変更されたテキストが必要ない場合は、DT_MODIFYSTRINGの使用を停止する必要があります。または、を使用して文字列をDrawTextに渡し、後でfilePath.GetBuffer()呼び出す必要があります。filePath.ReleaseBuffer()

于 2009-08-05T23:25:34.640 に答える
0

投稿したコードにはいくつかの矛盾があります。

'クラスファイル'の場合:

GetFileName() {return mFileName;}

ここに返品タイプはありませんか?また、FileContainerクラスでは、格納されている'File'オブジェクトをポインターとして定義しますが、GetFileName関数では、ポインターではないかのようにアクセスしますか?

File* mFile;
...
mFile.GetFileName();

なぜ今これがうまく起こっているのかについては、私にはよくわかりません。ただし、別の回避策は、GetFileName関数を変更してconst refを返すことです。これにより、戻り値が変更されないようにする必要があります。

const CString& GetFileName() { return mFileName; }
于 2009-08-05T23:09:50.150 に答える