該函數(shù)在erase一個(gè)元素的時(shí)候,先復(fù)制最近端,例如該元素靠近前端,那么該元素之前的所有元素被復(fù)制,并后移拷貝,達(dá)到覆蓋該元素的效果,導(dǎo)致最后Destroy的是第一個(gè)元素,析構(gòu)函數(shù)也是第一個(gè)元素的,由于第一個(gè)元素被復(fù)制了,所以第一個(gè)元素如果沒有拷貝復(fù)制函數(shù)來處理指針變量的話,那么之后第一個(gè)元素的副本中的指針將是錯誤的,而且同時(shí)有一個(gè)問題,我們想要destroy的那個(gè)元素的析構(gòu)函數(shù)沒被調(diào)用。
// TEMPLATE CLASS istream_iterator
template<class _Ty,
class _Elem = char,
class _Traits = char_traits<_Elem>,
class _Diff = ptrdiff_t>
class istream_iterator
: public iterator<input_iterator_tag, _Ty, _Diff,
const _Ty *, const _Ty&>
{ // wrap _Ty extracts from input stream as input iterator
typedef istream_iterator<_Ty, _Elem, _Traits, _Diff> _Myt;
public:
typedef _Elem char_type;
typedef _Traits traits_type;
typedef basic_istream<_Elem, _Traits> istream_type;
#if _SECURE_SCL
typedef _Range_checked_iterator_tag _Checked_iterator_category;
#endif
istream_iterator()
: _Myistr(0)
{ // construct singular iterator
}
istream_iterator(istream_type& _Istr)
: _Myistr(&_Istr)
{ // construct with input stream
_Getval();
}
const _Ty& operator*() const
{ // return designated value
#if _HAS_ITERATOR_DEBUGGING
if (_Myistr == 0)
{
_DEBUG_ERROR("istream_iterator is not dereferencable");
_SCL_SECURE_OUT_OF_RANGE;
}
#else
_SCL_SECURE_VALIDATE_RANGE(_Myistr != 0);
#endif /* _HAS_ITERATOR_DEBUGGING */
return (_Myval);
}
const _Ty *operator->() const
{ // return pointer to class object
return (&**this);
}
_Myt& operator++()
{ // preincrement
#if _HAS_ITERATOR_DEBUGGING
if (_Myistr == 0)
{
_DEBUG_ERROR("istream_iterator is not incrementable");
_SCL_SECURE_OUT_OF_RANGE;
}
#else
_SCL_SECURE_VALIDATE_RANGE(_Myistr != 0);
#endif /* _HAS_ITERATOR_DEBUGGING */
_Getval();
return (*this);
}
_Myt operator++(int)
{ // postincrement
_Myt _Tmp = *this;
++*this;
return (_Tmp);
}
bool _Equal(const _Myt& _Right) const
{ // test for iterator equality
return (_Myistr == _Right._Myistr);
}
protected:
void _Getval()
{ // get a _Ty value if possible
if (_Myistr != 0 && !(*_Myistr >> _Myval))
_Myistr = 0;
}
static void _Xran()
{ // report an out_of_range error
_THROW(out_of_range, "invalid istream_iterator");
}
istream_type *_Myistr; // pointer to input stream
_Ty _Myval; // lookahead value (valid if _Myistr is not null)
};
// istream_iterator TEMPLATE OPERATORS
template<class _Ty,
class _Elem,
class _Traits,
class _Diff> inline
bool operator==(
const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left,
const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right)
{ // test for istream_iterator equality
return (_Left._Equal(_Right));
}
template<class _Ty,
class _Elem,
class _Traits,
class _Diff> inline
bool operator!=(
const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left,
const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right)
{ // test for istream_iterator inequality
return (!(_Left == _Right));
}
紅色部分就是重點(diǎn)了,其實(shí)這種迭代器不能自增,只是不斷把流中的元素放到自己所存的值里,當(dāng)?shù)竭_(dá)流末尾時(shí),直接將判斷指針設(shè)為0。
摘要: //train.h#pragma once#include"stdafx.h"class Train{public: Train(int seatNum); virtual ~Train(void); bool ...
閱讀全文
以前一直理解錯誤,一直以為私有成員是對象的,不是類的,現(xiàn)在想想,自己真笨,編譯器怎么可能檢查到運(yùn)行時(shí)的對象的私有成員是否被別的代碼使用了呢?編譯器能做的只能是檢查類的聲明和定義,所以私有成員是類的,也就是同類所有對象的,而不是某一個(gè)對象的。只要在同一個(gè)類聲明和成員函數(shù)定義體內(nèi),私有成員是可以隨便使用的。
摘要: 1.這三個(gè)修飾符的基本意思 __cdecl:C調(diào)用方式,VC默認(rèn)使用該方式,參數(shù)從右向左傳遞,參數(shù)個(gè)數(shù)可變,棧的初始和清理由調(diào)用者完成 __stdcall:標(biāo)準(zhǔn)調(diào)用方式,多種語言使用這種調(diào)用方式,參數(shù)從右向左傳遞,參數(shù)個(gè)數(shù)不可變,棧的初始和清理由被調(diào)用者完成 __fastcall:參數(shù)盡量使用寄存...
閱讀全文
靜態(tài)鏈接的情況不考慮,因?yàn)檫@種情況就是把所有代碼合并到exe中,不需要進(jìn)入點(diǎn)。
進(jìn)入點(diǎn)就是系統(tǒng)在加載一個(gè)可執(zhí)行代碼塊(主要是exe和dll)到內(nèi)存的時(shí)候,系統(tǒng)將要調(diào)用的起始代碼的位置。
加載分為啟動時(shí)加載和運(yùn)行時(shí)加載,這兩種說法主要是針對dll的,因?yàn)閑xe加載必然會創(chuàng)建一個(gè)新的進(jìn)程,所以exe加載都是啟動時(shí)加載,就算是createprocess也應(yīng)該說是啟動時(shí)加載。而dll分為兩種情況,第一種就是隨著exe的加載一起加載到內(nèi)存的同一進(jìn)程地址空間中,另一種則是exe中的代碼loadlibrary在運(yùn)行時(shí)加載dll到當(dāng)前exe的進(jìn)程地址空間中。
無論上面哪種情況,只要加載,系統(tǒng)就會一定在加載的時(shí)候調(diào)用進(jìn)入點(diǎn)代碼,所以加載方式與進(jìn)入點(diǎn)完全不影響。
win sdk文檔中exe的進(jìn)入點(diǎn)有兩個(gè),一個(gè)是main,另一個(gè)是winmain,這個(gè)進(jìn)入點(diǎn)是可以改的,但是在c運(yùn)行環(huán)境下,連接器一般把進(jìn)入點(diǎn)默認(rèn)設(shè)置為mainCRTStartup和WinMainCRTStartup,因?yàn)閏運(yùn)行時(shí)需要在代碼執(zhí)行前進(jìn)行一些別的工作,所以就修改為前面兩個(gè)c入口點(diǎn),然后這兩個(gè)函數(shù)再分別調(diào)用main和winmain。c運(yùn)行時(shí)需要作的特別工作就是初始化c運(yùn)行時(shí)環(huán)境,包括靜態(tài)、全局變量和對象初始化。當(dāng)main或者winmain返回時(shí)就又回到了前兩個(gè)函數(shù)中,這兩個(gè)函數(shù)的后半部分就是負(fù)責(zé)清理之前的初始化工作。
win sdk文檔中的dll的進(jìn)入店是dllmain,同樣在c運(yùn)行時(shí)下,改為_DllMainCRTStartup,系統(tǒng)加載dll時(shí)調(diào)用這個(gè)函數(shù),然后這個(gè)函數(shù)做些初始化工作,再調(diào)用dllmain,然后返回_DllMainCRTStartup結(jié)束執(zhí)行。此時(shí),dll已經(jīng)在進(jìn)程的地址空間中了,該進(jìn)程的exe可以使用dll中的代碼了。如果該dll是啟動時(shí)加載,那么在程序結(jié)束時(shí)會再次調(diào)用_DllMainCRTStartup進(jìn)行清理之前dll初始化的工作,如果是通過loadlibrary來運(yùn)行時(shí)加載dll,那么需要exe自己卸載dll,卸載的時(shí)候會再次調(diào)用_DllMainCRTStartup