该函数在erase一个元素的时候,先复制最近端,例如该元素靠近前端,那么该元素之前的所有元素被复制,并后移拷贝,达到覆盖该元素的效果,导致最后Destroy的是第一个元素,析构函数也是第一个元素的,由于第一个元素被复制了,所以第一个元素如果没有拷贝复制函数来处理指针变量的话,那么之后第一个元素的副本中的指针将是错误的,而且同时有一个问题,我们想要destroy的那个元素的析构函数没被调用。
// 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));
}
红色部分就是重点了,其实这种迭代器不能自增,只是不断把流中的元素放到自己所存的值里,当到达流末尾时,直接将判断指针设为0。
摘要: //train.h#pragma once#include"stdafx.h"class Train{public: Train(int seatNum); virtual ~Train(void); bool ...
阅读全文
以前一直理解错误,一直以为私有成员是对象的,不是类的,现在想想,自己真笨,编译器怎么可能检查到运行时的对象的私有成员是否被别的代码使用了呢?编译器能做的只能是检查类的声明和定义,所以私有成员是类的,也就是同类所有对象的,而不是某一个对象的。只要在同一个类声明和成员函数定义体内,私有成员是可以随便使用的。
摘要: 1.这三个修饰符的基本意思 __cdecl:C调用方式,VC默认使用该方式,参数从右向左传递,参数个数可变,栈的初始和清理由调用者完成 __stdcall:标准调用方式,多种语言使用这种调用方式,参数从右向左传递,参数个数不可变,栈的初始和清理由被调用者完成 __fastcall:参数尽量使用寄存...
阅读全文
静态链接的情况不考虑,因为这种情况就是把所有代码合并到exe中,不需要进入点。
进入点就是系统在加载一个可执行代码块(主要是exe和dll)到内存的时候,系统将要调用的起始代码的位置。
加载分为启动时加载和运行时加载,这两种说法主要是针对dll的,因为exe加载必然会创建一个新的进程,所以exe加载都是启动时加载,就算是createprocess也应该说是启动时加载。而dll分为两种情况,第一种就是随着exe的加载一起加载到内存的同一进程地址空间中,另一种则是exe中的代码loadlibrary在运行时加载dll到当前exe的进程地址空间中。
无论上面哪种情况,只要加载,系统就会一定在加载的时候调用进入点代码,所以加载方式与进入点完全不影响。
win sdk文档中exe的进入点有两个,一个是main,另一个是winmain,这个进入点是可以改的,但是在c运行环境下,连接器一般把进入点默认设置为mainCRTStartup和WinMainCRTStartup,因为c运行时需要在代码执行前进行一些别的工作,所以就修改为前面两个c入口点,然后这两个函数再分别调用main和winmain。c运行时需要作的特别工作就是初始化c运行时环境,包括静态、全局变量和对象初始化。当main或者winmain返回时就又回到了前两个函数中,这两个函数的后半部分就是负责清理之前的初始化工作。
win sdk文档中的dll的进入店是dllmain,同样在c运行时下,改为_DllMainCRTStartup,系统加载dll时调用这个函数,然后这个函数做些初始化工作,再调用dllmain,然后返回_DllMainCRTStartup结束执行。此时,dll已经在进程的地址空间中了,该进程的exe可以使用dll中的代码了。如果该dll是启动时加载,那么在程序结束时会再次调用_DllMainCRTStartup进行清理之前dll初始化的工作,如果是通过loadlibrary来运行时加载dll,那么需要exe自己卸载dll,卸载的时候会再次调用_DllMainCRTStartup