问题求教

Fleeboy 2009-12-20 12:02:39
我也曾经碰到过类似问题,那位高手能解释http://blog.csdn.net/pathuang68/archive/2009/12/19/5040842.aspx一文中提出的问题?谢谢
...全文
217 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
baihacker 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 fleeboy 的回复:]
按照飞雪大哥在11楼的说法:
引用 11 楼 baihacker 的回复:
svec.erase(iter);
容器元素有变化了...
原有的迭代器失效.
2,3楼已经说了...


那么是不是说7楼和8楼中的iter已经是无效了?
如果是,即iter无效,那么7楼和8楼为什么还在继续使用iter,而且结果正确?
如果不是,即iter依然有效,那么6楼为什么就会出现错误?
[/Quote]
...通过让iter赋值为erase,改变了iter的状态了...

失效不是说iter本身坏掉了,再也不能用了,而是指处于一个非法的状态,行为不在你预料之中.

比如int* ptr = &a;
ptr = NULL;
现在ptr失效....
ptr = &a;
现在ptr又可以了...
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
按照飞雪大哥在11楼的说法:
[Quote=引用 11 楼 baihacker 的回复:]
svec.erase(iter);
容器元素有变化了...
原有的迭代器失效.
2,3楼已经说了...
[/Quote]

那么是不是说7楼和8楼中的iter已经是无效了?
如果是,即iter无效,那么7楼和8楼为什么还在继续使用iter,而且结果正确?
如果不是,即iter依然有效,那么6楼为什么就会出现错误?
baihacker 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 fleeboy 的回复:]
谢面色铁路桥在15楼的恢复,但是erase的返回值是:
A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence.

也就是说erase返回的是被删除元素后面的那个元素,这也是为什么我在6楼这么写的原因:
C/C++ codefor(vector<Student>::iterator iter= svec.begin(); iter!= svec.end(); iter++)
{
iter= svec.erase(iter);
iter--;
}
面色铁路桥在15楼的说法我相信是对的,不然VC2005也不会报错。如果iter = svec.erase(iter);返回的是svec.begin(),那么岂不是和上面那段英文描述的内容冲突了吗?即erase返回的是被删除元素后面的那个元素。

这又如何解释呢?
[/Quote]
如果删除后只有一个元素...
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
谢面色铁路桥在15楼的恢复,但是erase的返回值是:
A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence.

也就是说erase返回的是被删除元素后面的那个元素,这也是为什么我在6楼这么写的原因:

for(vector<Student>::iterator iter = svec.begin(); iter != svec.end(); iter++)
{
iter = svec.erase(iter);
iter--;
}

面色铁路桥在15楼的说法我相信是对的,不然VC2005也不会报错。如果iter = svec.erase(iter);返回的是svec.begin(),那么岂不是和上面那段英文描述的内容冲突了吗?即erase返回的是被删除元素后面的那个元素。

这又如何解释呢?
baihacker 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 fleeboy 的回复:]
嗯。但飞雪大哥和面色铁路桥分别在7楼和8楼中,不是还在使用原来的迭代器吗?越来越糊涂了:(
[/Quote]
注意erase
c.erase(pos) Removes the element at iterator position pos and returns the position of the next element
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
老邓13楼那个代码,看得头晕...
mstlq 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 loaden 的回复:]
引用 10 楼 fleeboy 的回复:
两位给的解正确。现在我的问题是:6楼那样的写法为什么不正确呢?

之前的iterator全部失效,你还--,不就非法了吗?
[/Quote]

针对6楼的具体情况……
不能这么说……

具体情况具体分析,6楼代码的问题是……


int main(void)
{
{
vector<Student> svec;
Student stu01;
Student stu02("Bob", 6);
Student stu03("Chris", 5);

svec.push_back(stu01);
svec.push_back(stu02);
svec.push_back(stu03);

for(vector<Student>::iterator iter = svec.begin(); iter != svec.end(); iter++)
{
iter = svec.erase(iter);
//知道这个时候iter等于什么吗?等于svec.begin()!!虽然这个begin已经不是原来的那个begin了……
//begin-1是什么东西,真是天晓得咯,这种操作,出什么问题都有可能……
iter--;
}
}

return 0;
}
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
嗯。但飞雪大哥和面色铁路桥分别在7楼和8楼中,不是还在使用原来的迭代器吗?越来越糊涂了:(
老邓 2009-12-20
  • 打赏
  • 举报
回复
楼主自己搞定一个Vector,会体会的更深一些。
这是我现在用的:不调用构造函数。
// !注意:T不能用对象,因为使用malloc/free操作内存
template <typename T>
class Vector : private UnCopy
{
public:
Vector() : m_buf(NULL), m_size(0), m_capacity(0) {}
Vector(WORD size) : m_buf(NULL), m_size(0), m_capacity(size)
{
if (size != 0) qpMalloc(m_buf, T, m_capacity);
}
~Vector() { Clear(); }

public:
bool Add(const T& value, bool minMemory = false)
{
if (m_capacity == 0 && m_buf == NULL)
{
qpMalloc(m_buf, T, 1);
if (m_buf == NULL) return false;
++m_capacity;
}

if (m_capacity == m_size || (minMemory && m_capacity - m_size != 1))
{
DWORD newSize = m_size + (minMemory ? 1 : (m_size < 5 ? (m_capacity + 1) : (1 + m_size / 10)));
if (newSize > USHRT_MAX) return false;
qpMallocEx(p, T, newSize);
if (p == NULL) return false;
m_capacity = static_cast<WORD>(newSize);
::memcpy(p, m_buf, m_size * sizeof(T));
qpFree(m_buf);
m_buf = p;
}

::memcpy(m_buf + m_size++, &value, sizeof(T));
return true;
}

bool Remove(const T& value, bool minMemory = false)
{
for (WORD pos = 0; pos < m_size; ++pos)
{
if (m_buf[pos] == value)
{
if (m_capacity == 1) { Clear(); return true; }
if (minMemory || m_capacity - m_size > 5)
{
qpMallocEx(p, T, m_size - 1);
if (p == NULL) return false;
--m_capacity;
::memcpy(p, m_buf, pos * sizeof(T));
::memcpy(p + pos, m_buf + pos + 1, (--m_size - pos) * sizeof(T));
qpFree(m_buf);
m_buf = p;
}
else
{
::memmove(m_buf + pos, m_buf + pos + 1, (--m_size - pos) * sizeof(T));
}
return true;
}
}
return false;
}

bool Resize(WORD size)
{
qpASSERT(size > 0);
if (size == m_capacity) return false;
qpMallocEx(p, T, size);
if (p == NULL) return false;
m_capacity = size;
::memcpy(p, m_buf, (size < m_size ? size : m_size) * sizeof(T));
qpFree(m_buf);
m_buf = p;
if (m_size > size) m_size = size;
return true;
}

T* Find(const T& value)
{
for (WORD pos = 0; pos < m_size; ++pos)
if (m_buf[pos] == value) return m_buf + pos;
return NULL;
}

bool Swap(WORD left, WORD right)
{
qpASSERT(left != right && left < m_size && right < m_size);
if (m_buf == NULL) return qpDbgError();
std::swap(m_buf[left], m_buf[right]);
return true;
}

bool Sort()
{
if (m_buf == NULL) return qpDbgError();
std::sort(m_buf, m_buf + m_size);
return true;
}

bool Exist(const T& value)
{
if (m_buf == NULL) return qpDbgError();

int low = 0;
int high = m_size;
while (low <= high)
{
int middle = (low + high) / 2;
if (value == m_buf[middle]) return true;
else if (value < m_buf[middle]) high = middle - 1;
else low = middle + 1;
}
return false;
}

short Distance(const T* value)
{
return static_cast<short>(value - m_buf);
}

T& operator [](WORD pos) { qpASSERT(m_buf); return m_buf[pos]; }
T& Get(WORD pos) { qpASSERT(m_buf); return m_buf[pos]; }
void Clear() { qpFree(m_buf); m_size = 0; m_capacity = 0; }
WORD Size() const { return m_size; }
WORD Capacity() const { return m_capacity; }

private:
T* m_buf;
WORD m_size;
WORD m_capacity;
};
老邓 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 fleeboy 的回复:]
两位给的解正确。现在我的问题是:6楼那样的写法为什么不正确呢?
[/Quote]
之前的iterator全部失效,你还--,不就非法了吗?
baihacker 2009-12-20
  • 打赏
  • 举报
回复
svec.erase(iter);
容器元素有变化了...
原有的迭代器失效.
2,3楼已经说了...
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
两位给的解正确。现在我的问题是:6楼那样的写法为什么不正确呢?
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
谢谢飞雪大哥,小弟再去试试。
您已经帮我解决第一个问题了“容器的元素应当具有值语义,如果是具有指针语义(有的又称为引用语义)的话,应当自己解决.”等会我会好好读读您给的那段e文。:)
mstlq 2009-12-20
  • 打赏
  • 举报
回复
只是为了全删?
那么连--操作都不用……

int main(void)
{
{
vector<Student> svec;
Student stu01;
Student stu02("Bob", 6);
Student stu03("Chris", 5);

svec.push_back(stu01);
svec.push_back(stu02);
svec.push_back(stu03);

for(vector<Student>::iterator iter = svec.begin(); iter != svec.end(); )
{
iter = svec.erase(iter);//自动指向被删除元素的下一个
}
}

return 0;
}
baihacker 2009-12-20
  • 打赏
  • 举报
回复
        for(vector<Student>::iterator iter = svec.begin(); iter != svec.end();)
{
iter = svec.erase(iter);
}
Fleeboy 2009-12-20
  • 打赏
  • 举报
回复
谢谢飞雪大哥和面色铁路桥的提醒,但就算我改成如下代码,也还有运行时问题:

int main(void)
{
{
vector<Student> svec;
Student stu01;
Student stu02("Bob", 6);
Student stu03("Chris", 5);

svec.push_back(stu01);
svec.push_back(stu02);
svec.push_back(stu03);

for(vector<Student>::iterator iter = svec.begin(); iter != svec.end(); iter++)
{
iter = svec.erase(iter);
iter--;
}
}

return 0;
}
baihacker 2009-12-20
  • 打赏
  • 举报
回复
下面是引用自The C++ Standard Library的一些话


5.10 Container Elements
Elements of containers must meet certain requirements because containers handle them in a special way. In this section I describe these requirements. I also discuss the consequences of the fact that containers make copies of their elements internally.

5.10.1 Requirements for Container Elements
Containers, iterators, and algorithms of the STL are templates. Thus, they can process any type, whether predefined or user defined. However, because of the operations that are called, some requirements apply. The elements of STL containers must meet the following three fundamental requirements:

An element must be copyable by a copy constructor. The generated copy should be equivalent to the source. This means that any test for equality returns that both are equal and that both source and copy behave the same.

All containers create internal copies of their elements and return temporary copies of them, so the copy constructor is called very often. Thus, the copy constructor should perform well (this is not a requirement, but a hint to get better performance). If copying objects takes too much time you can avoid copying objects by using the containers with reference semantics. See Section 6.8, for details.

An element must be assignable by the assignment operator. Containers and algorithms use assignment operators to overwrite old elements with new elements.

An element must be destroyable by a destructor. Containers destroy their internal copies of elements when these elements are removed from the container. Thus, the destructor must not be private. Also, as usual in C++, a destructor must not throw; otherwise, all bets are off.

These three operations are generated implicitly for any class. Thus, a class meets the requirements automatically, provided no special versions of these operations are defined and no special members disable the sanity of those operations.

Elements might also have to meet the following requirements [16] :

[16] In some older C++ systems, you may have to implement these additional requirements even if they are not used. For example, some implementations of vector always require the default constructor for elements. Other implementations always require the existence of the comparison operator. However, according to the standard, such a requirement is wrong, and these limitations will likely be eliminated.

For some member functions of sequence containers, the default constructor must be available. For example, it is possible to create a nonempty container or increase the number of elements with no hint of the values those new elements should have. These elements are created without any arguments by calling the default constructor of their type.

For several operations, the test of equality with operator == must be defined. It is especially needed when elements are searched.

For associative containers the operations of the sorting criterion must be provided by the elements. By default, this is the operator <, which is called by the less<> function object.

5.10.2 Value Semantics or Reference Semantics
All containers create internal copies of their elements and return copies of those elements. This means that container elements are equal but not identical to the objects you put into the container. If you modify objects as elements of the container, you modify a copy, not the original object.

Copying values means that the STL containers provide value semantics. They contain the values of the objects you insert rather than the objects themselves. In practice, however, you also need reference semantics. This means that the containers contain references to the objects that are their elements.

The approach of the STL, only to support value semantics, has strengths and weaknesses. Its strengths are:

Copying elements is simple.

References are error prone. You must ensure that references don't refer to objects that no longer exist. You also have to manage circular references, which might occur.

Its weaknesses are:

Copying elements might result in bad performance or may not even be possible.

Managing the same object in several containers at the same time is not possible.

In practice you need both approaches; you need copies that are independent of the original data (value semantics) and copies that still refer to the original data and get modified accordingly (reference semnatics). Unfortunately, there is no support for reference semantics in the C++ standard library. However, you can implement reference semantics in terms of value semantics.

The obvious approach to implementing reference semantics is to use pointers as elements. [17] However, ordinary pointers have the usual problems. For example, objects to which they refer may no longer exist, and comparisons may not work as desired because pointers instead of the objects are compared. Thus, you should be very careful when you use ordinary pointers as container elements.

[17] C programmers might recognize the use of pointers to get reference semantics. In C, function arguments are able to get passed only by value, so you need pointers to enable a call-by-reference.

A better approach is to use a kind of smart pointer — objects that have a pointer-like interface but that do some additional checking or processing internally. The important question here is, how smart do they have to be? The C++ standard library does provide a smart pointer class that might look like it would be useful here: auto_ptr (see Section 4.2). However, you can't use auto_ptrs because they don't meet a fundamental requirement for container elements. That is, after a copy or an assignment of an auto_ptr is made, source and destination are not equivalent. In fact, the source auto_ptr gets modified because its value gets transferred and not copied(see page 43 and page 47). In practice, this means that sorting or even printing the elements of a container might destroy them. So, do not use auto.ptrs as container elements (if you have a standard-conforming C++ system, you will get an error at compile time if you try to use an auto_ptr as a container element). See page 43 for details.

To get reference semantics for STL containers you must write your own smart pointer class. But be aware: Even if you use a smart pointer with reference counting (a smart pointer that destroys its value automatically when the last reference to it gets destroyed), it is troublesome. For example, if you have direct access to the elements, you can modify their values while they are in the container. Thus, you could break the order of elements in an associative container. You don't want to do this.

Section 6.8, offers more details about containers with reference semantics. In particular, it shows a possible way to implement reference semantics for STL containers by using smart pointers with reference counting.

I l@ve RuBoard
baihacker 2009-12-20
  • 打赏
  • 举报
回复
容器的元素应当具有值语义,如果是具有指针语义(有的又称为引用语义)的话,应当自己解决.
baihacker 2009-12-20
  • 打赏
  • 举报
回复
情形3:如果将main函数改写成:

在容器有变动的时候,先前的迭代器失效,行为未定义.
mstlq 2009-12-20
  • 打赏
  • 举报
回复
erase可能导致迭代器失效……
出现问题是自找的……

svec.erase(iter);
iter--;

需要改成

iter=svec.erase(iter);
iter--

加载更多回复(5)

64,686

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧