開発環境:Windows98/VC++6.0sp5pro/SDK-may2002/ATL3.0/WTL7.0
※MFC不使用
後掲のソースで、Func()を抜けるときに以下のエラーが発生します。
なお、Func()は、別の関数から呼ばれています。
> ハンドルされていない例外は MyApp.exeにあります:
> 0xC0000005: Access Violation。
//------------------------------------------------------------
// ...\Vc98\Include\List.h
//------------------------------------------------------------
template<class _Ty, class _A = allocator<_Ty> >
class list {
class iterator : public const_iterator {
iterator& operator++()
{_Ptr = _Acc::_Next(_Ptr); // ← ここでブレーク
return (*this); }
//------------------------------------------------------------
// 以下、自作ソースの一部
//------------------------------------------------------------
template <class T>
class MyList
{
protected:
typedef std::list<T> _MyList;
_MyList* m_List;
_MyList::iterator m_it;
int m_nSeekPtr;
public:
MyList() : m_List(NULL) {
m_List = new _MyList;
}
virtual ~MyList() {
delete m_List;
}
int GetSize() const {
return static_cast<int>(m_List->size()); // m_List->size()
returns size_t
}
T GetAt(const int& nIndex = 0) {
m_it = m_List->begin();
std::advance(m_it, nIndex);
return *m_it;
}
void Append(const T& objNewData) {
m_List->push_back(objNewData);
}
};
class MyCStringList : public MyList<CString> {}; // 省略なし
BOOL MakeSection(const MyCStringList& listrGot, LPCTSTR szFile, LPCTSTR
szSection, const DWORD& dwBufferSize = SHRT_MAX - 1) {
MyCStringList listrData = static_cast<MyCStringList>(listrGot);
TCHAR *pszWriteData = new TCHAR [dwBufferSize + 1];
::memset(pszWriteData, 0, static_cast<size_t>(dwBufferSize + 1));
int nPtr = 0, nLen = 0;
CString str;
for (DWORD i = 0; i < listrData.GetSize(); ++i) {
str.Format(_T(%02ld=), i + 1);
str += listrData.GetAt(i);
nLen = str.GetLength() + 1;
if (nPtr + nLen > dwBufferSize) { // バッファー不足
delete [] pszWriteData;
return FALSE;
}
::lstrcpyn(pszWriteData + nPtr, str + _T(\0\0), nLen + 1);
nPtr += nLen;
}
// output data
const int nRet = ::WritePrivateProfileSection(szSection,
pszWriteData, szFile);
::WritePrivateProfileString(NULL, NULL, NULL, szFile); // バッファをフ
ラッシュ
delete [] pszWriteData;
return (nRet) ? TRUE : FALSE;
}
void Func() {
MyCStringList listrTest;
// テスト用文字列を追加
listrTest.Append(_T(string1));
listrTest.Append(_T(string2));
listrTest.Append(_T(string3));
CString strPath = _T(");
::GetModuleFileName(_Module.GetModuleInstance(),
strPath.GetBufferSetLength(MAX_PATH), MAX_PATH);
strPath.ReleaseBuffer();
const int nPos = strPath.ReverseFind(_T('\\'));
if (nPos < 0) {
ATLASSERT( FALSE );
return;
}
strPath = strPath.Left(nPos + 1) + _T(test.ini);
BOOL bRet = MakeSection(listrTest, static_cast<LPCTSTR>(strPath), _T
(test), 100);
ATLASSERT( bRet );
}
//------------------------------------------------------------
// Test.ini への出力結果
//------------------------------------------------------------
[test]
01=string1
02=string2
03=string3
(1) デバッガで調べたところ、MakeSection() にて、
MyCStringList listrData = static_cast<MyCStringList>(listrGot);
としたときの listrData と listrGotの中身のアドレスが同じなのです。
私は、こうすると別のオブジェクトが用意され、中身が物理的に複製
されると考えていたのですが、間違っているのでしょうか。
(2) また、listrData と、listrGot が指す先が同一だとすると、
MakeSection()を抜けるときに、listrGot が開放され、その結果
listrData の値が不定となり、アクセス違反が発生してまう、
ということなのでしょうか。
→さらに、この場合、どのように対処すればよろしいのでしょうか。
(3) その他、何かおかしいところがあれば、指摘くださると幸いです。
MyList<T>::m_List は list<T>の'ポインタ'です。
MyCStringList listData = static_cast<MyCStringList>(listrGot);
によってコピーが作られますが、ポインタのコピーは一つの実体を
複数のポインタが指している状態となります。
よーするに listData.m_List == listGot.m_List です。
listDataがデストラクトされるとき、delete m_List しているので、
元ネタをもぶっ壊します。
επιστημηさん、回答ありがとうございます。
CStringクラスを参考に、参照カウンタを持たせようかとも思いましたが、
私には実装は難しすぎたため、ポインタで保持するのを止め、
> _MyList* m_List;
_MyList m_List; とすることにしました。
ありがとうございました。
boost::shared_ptrあたりを使ってみますか?
boost::shared_ptr ですか。いいですね。
今度試してみます。貴重な情報ありがとうございます。