关于std库容器上的析构函数的问题 [英] Questions about destructors on std library containers

查看:81
本文介绍了关于std库容器上的析构函数的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解在什么情况下使用std :: vector将析构函数称为

。我有一个应用程序,我将在向量中放置实际对象,

而不仅仅是指针。


1.标准说空()有不断复杂。如果它实际上是每个对象称为析构函数,那么在我看来它将具有线性复杂度。 empty()是否为

容器中的每个对象调用析构函数?如果是的话,为什么它被描述为具有不变的复杂性?

如果不是,这似乎也是一个问题。


2.标准描述清楚说明它表现得像

erase(开始,结束)。这好像它会抹掉第一个元素,复制

所有成功的元素,依此类推,这显然非常低效。是否可以安全地假设更合理的事情发生了?

封底?


3.擦除是否为要删除的元素调用析构函数?

更合适的是,我想我应该问清楚在清除物品后移动
后最后释放的元素。我可能只会在整个矢量或其最后一个元素上擦除




正如我写这篇文章我意识到我可能有一个基本的混乱,并且

构造函数和析构函数只在向量的生命开始和结束时被调用(当它的容量扩展时)。

时间元素的其余部分是否正在使用中,并且分配的行为

运算符是关键。这是真的发生了什么?

我对从标准中能够和不能推断的内容感兴趣,并且

当前是什么不同平台上的编译器实践 - 换句话说,

在可移植代码中可以安全地假设。

解决方案

< blockquote>罗斯博伊兰 <滚装******** @ stanfordalumni.org>写道...

我试图理解在什么情况下使用std :: vector将析构函数称为
。我有一个应用程序,我将在向量中放置实际对象,而不仅仅是指针。

1.标准说empty()具有不变的复杂性。如果它实际上为每个对象调用析构函数,在我看来它将具有线性复杂性。 empty()是否为
容器中的每个对象调用析构函数?如果是的话,为什么它被描述为具有不变的复杂性?
如果不是,那似乎也是一个问题。


''empty''与''clear''不同。不要混淆两者。对于C ++

库容器,''empty''是一个形容词,而不是一个动词。

2.标准描述清楚,它表现得像
擦除(开始,结束)。这好像它会抹掉第一个元素,
复制所有的元素,依此类推,这显然非常低效。假设有更合理的事情发生在幕后是否安全?


绝对。当解释语义时,并不意味着

实现完全相同。不要混淆语义和

实现。

3.擦除调用析构函数来删除元素吗?


是的。

更合适的是,我想我应该问一下,在移除已擦除的项目后,最后释放的元素是否被清除。


我不确定我是否完全理解这句话,但是在移动过程中,即使在擦除过程中,元素也可以被释放。 std :: vector

是一个棘手的容器,它必须重新分配并移动所有

时间的东西,所以旧的元素将在新的
副本之后被销毁/>
他们是。

我可能只会删除整个矢量或其最后一个元素。


唐'没有任何区别,他们仍然会被摧毁。 Hafta。

当我写这篇文章时,我意识到我可能有一个基本的困惑,并且
构造函数和析构函数只在向量的开头和结尾调用
生命(当它的能力扩大时)。


....当你插入或删除中间的元素时。 IOW,每个

时间元素都会被移动。

其余的
时间元素是否正在使用中,具有$ b $的行为b赋值运算符是键。这是真的发生了什么?


很多。为什么不跟踪所有构造函数和析构函数调用?这是好玩的,而且很有教育意义。这是教育上的乐趣。

我对从标准中可以推断和不能推断的内容感兴趣,
以及在不同平台上当前的编译器实践是 - -in其他的
字,在便携式代码中可以安全地假设。




没有什么是安全的,除了标准中所说的内容。


V


" Ross Boylan" <滚装******** @ stanfordalumni.org>在留言中写道

news:pa **************************** @ stanfordalumni .org ... < blockquote class =post_quotes>我试图理解在什么情况下使用std :: vector将析构函数称为
。我有一个应用程序,我将在向量中放置实际对象,而不仅仅是指针。

1.标准说empty()具有不变的复杂性。如果它实际上为每个对象调用析构函数,在我看来它将具有线性复杂性。 empty()是否为
容器中的每个对象调用析构函数?如果是的话,为什么它被描述为具有不变的复杂性?
如果不是,那似乎也是一个问题。


empty()的符合实现是:return this-> size()> 0;

此函数不会清空向量(与clear()不同):它只有

返回一个布尔值,指示容器是否为空。

2.标准描述明确表示它的行为类似于擦除(开始,结束)。这好像它会抹掉第一个元素,
复制所有的元素,依此类推,这显然非常低效。假设有更合理的事情发生在幕后是否安全?
erase()不会逐个删除元素:通过在其上复制/移动以下元素,整个范围被删除

。然后删除未使用的尾随

元素。

如果ABCDEFGH的前三个元素被删除,通常会发生以下步骤:
通常会发生:

使用赋值运算符复制DEFGH - > DEFGHFGH

尾随元素被破坏 - > DEFGH

3.擦除调用析构函数以删除元素吗?
是的。更准确的说,我想我应该问一下,在移除已擦除的项目后,最后释放的元素是否被清除。我可能只会删除整个矢量或它的最后一个元素。
这意味着你可以分别调用clear()和pop_back(),

而不是erase()。

我正在写这个我意识到我可能有一个基本的混淆,并且
构造函数和析构函数只在向量的生命的开始和结束时被调用(当它的容量扩展时)。其余的
时间元素正在使用或不使用,
赋值运算符的行为是关键。这是真的发生了什么?


向量的容量仅作为原始内存分配。

向量中构造的对象数始终等于

vector :: size()返回的值。

我对从标准,
和当前编译器中可以推断出的内容感兴趣在不同的平台上练习 - 用其他
的话说,在便携式代码中可以安全地假设。



没有''ghost''对象可以由std构建:: vector,给出比:

- std :: vector中包含的元素可能没有默认值

构造函数

- 保持隐藏已被删除的元素副本将会产生意外影响 - 并且是不允许的。


hth,Ivan

- -
http://ivan.vecerina.com/contact/ ?subject = NG_POST < - 电子邮件联系表格



" Ivan Vecerina" < PL ***************** @ ivan.vecerina.com>在消息中写道

news:c0 ********** @ newshispeed.ch ...

" Ross Boylan" <滚装******** @ stanfordalumni.org>在消息中写道
新闻:pa **************************** @ stanfordalumni .org ...

我试图理解在什么情况下使用std :: vector将析构函数称为
。我有一个应用程序,我将在向量中放置实际对象,而不仅仅是指针。

1.标准说empty()具有不变的复杂性。如果它实际上为每个对象调用析构函数,在我看来它将具有线性复杂性。 empty()是否为


容器中的每个对象调用析构函数?如果是的话,为什么它被描述为具有不变的复杂性?
如果不是,那似乎也是一个问题。



一个符合的empty()实现是:return this- > size()> 0;
此函数不会清空向量(与clear()不同):它只返回一个布尔值,指示容器是否为空。



Josuttis在他的书The C ++ standard library中建议空()超过

container.size()> 0.他说它实际上更有效率。

鉴于此实现,这可能不是真的。

2.标准描述清楚,它表现得像擦除(开始,结束)。这好像它会抹掉第一个元素,


复制

所有的元素,依此类推,这显然非常低效。假设一些更合理的事情在掩护下发生是否安全?


erase()不会逐个删除元素:整个范围被删除
复制/移动以下元素。然后删除未使用的尾随
元素。
如果ABCDEFGH的前三个元素被删除,通常会发生的步骤是:
使用赋值运算符复制DEFGH - > DEFGHFGH
尾随元素被破坏 - > DEFGH



hmm..IIRC,它们不是。

必须注意擦除尾随元素(即FGH)。


祝福,

Sharad


I am trying to understand under what circumstances destructors get called
with std::vector. I have an application in which I will put real objects,
not just pointers, in the vector.

1. The standard says that empty() has constant complexity. If it actually
called the destructor for each object, it seems to me it would have
linear complexity. Does empty() call the destructor for each object in the
container? If yes, why is it described as having constant commplexity?
If no, that seems like a problem too.

2. The standard describes clear by saying that it behaves like
erase(begin, end). That seems as if it would erase the first element, copying
all succedding elements over it, and so on, which is obviously very
inefficient. Is it safe to assume something more reasonable is happening
under the covers?

3. Does erase call the destructor for the elements erased?
More properly, I guess I should ask if the elements freed at the end after
being moved over erased items are cleared. I''d probably only be erasing
the whole vector or its last element.

As I''m writing this I realize I may have a basic confusion, and that
constructors and destructors are only called at the beginning and end
of the vector''s life (and when its capacity expands). The rest of the
time elements are either in use or not, with the behavior of the assignment
operator being key. Is that what''s really going on?
I''m interested both in what can and can''t be inferred from the standard, and
in what current compiler practice on different platforms is--in other words,
what''s safe to assume in portable code.

解决方案

"Ross Boylan" <Ro********@stanfordalumni.org> wrote...

I am trying to understand under what circumstances destructors get called
with std::vector. I have an application in which I will put real objects,
not just pointers, in the vector.

1. The standard says that empty() has constant complexity. If it actually
called the destructor for each object, it seems to me it would have
linear complexity. Does empty() call the destructor for each object in the container? If yes, why is it described as having constant commplexity?
If no, that seems like a problem too.
''empty'' is not the same as ''clear''. Do not confuse the two. For C++
library containers, ''empty'' is an adjective, not a verb.
2. The standard describes clear by saying that it behaves like
erase(begin, end). That seems as if it would erase the first element, copying all succedding elements over it, and so on, which is obviously very
inefficient. Is it safe to assume something more reasonable is happening
under the covers?
Absolutely. When semantics are explained, it doesn''t mean that the
implementation is precisely the same. Do not confuse semantics and
implementation.

3. Does erase call the destructor for the elements erased?
Yes.
More properly, I guess I should ask if the elements freed at the end after
being moved over erased items are cleared.
I am not sure I completely understand the sentence, but elements can
be freed even in the middle of erasing, during the move. std::vector
is a tricky container, it has to reallocate and move things all the
time, so the old elements will get destroyed right after new copies of
them are made.
I''d probably only be erasing
the whole vector or its last element.
Don'' make no difference, they are still gonna get destroyed. Hafta.

As I''m writing this I realize I may have a basic confusion, and that
constructors and destructors are only called at the beginning and end
of the vector''s life (and when its capacity expands).
....and when you insert or remove an element in the middle. IOW, every
time elements get moved around.
The rest of the
time elements are either in use or not, with the behavior of the assignment operator being key. Is that what''s really going on?
Plenty. Why not trace all the constructor and destructor calls? It''s
fun and it''s educational. It''s educational fun.
I''m interested both in what can and can''t be inferred from the standard, and in what current compiler practice on different platforms is--in other words, what''s safe to assume in portable code.



Nothing is safe to assume except what''s said in the Standard.

V


"Ross Boylan" <Ro********@stanfordalumni.org> wrote in message
news:pa****************************@stanfordalumni .org...

I am trying to understand under what circumstances destructors get called
with std::vector. I have an application in which I will put real objects,
not just pointers, in the vector.

1. The standard says that empty() has constant complexity. If it actually
called the destructor for each object, it seems to me it would have
linear complexity. Does empty() call the destructor for each object in the container? If yes, why is it described as having constant commplexity?
If no, that seems like a problem too.
A conforming implementation of empty() is: return this->size() > 0;
This function does not empty the vector ( unlike clear() ): it only
returns a boolean that indicates whether the container is empty or not.
2. The standard describes clear by saying that it behaves like
erase(begin, end). That seems as if it would erase the first element, copying all succedding elements over it, and so on, which is obviously very
inefficient. Is it safe to assume something more reasonable is happening
under the covers? erase() does not remove elements one by one: the whole range is "removed"
by copying/moving the following elements over it. Then the unused trailing
elements are removed.
Say if the first three elements of ABCDEFGH are erased, steps that will
typically happen are:
DEFGH are copied down using the assignment operator --> DEFGHFGH
The trailing elements are destroyed --> DEFGH
3. Does erase call the destructor for the elements erased? Yes. More properly, I guess I should ask if the elements freed at the end after
being moved over erased items are cleared. I''d probably only be erasing
the whole vector or its last element. Which means you can call clear() and pop_back(), respectively,
instead of erase().
As I''m writing this I realize I may have a basic confusion, and that
constructors and destructors are only called at the beginning and end
of the vector''s life (and when its capacity expands). The rest of the
time elements are either in use or not, with the behavior of the assignment operator being key. Is that what''s really going on?
The capacity of a vector is only allocated as raw memory.
The number of constructed objects within the vector is always equal to
the value returned by vector::size().
I''m interested both in what can and can''t be inferred from the standard, and in what current compiler practice on different platforms is--in other words, what''s safe to assume in portable code.


No ''ghost'' objects can be constructed by std::vector, given than:
- the element contained in an std::vector may not have a default
constructor
- keeping hidden copies of elements that have been erased would have
unexpected effects -- and is not allowed.

hth, Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form



"Ivan Vecerina" <pl*****************@ivan.vecerina.com> wrote in message
news:c0**********@newshispeed.ch...

"Ross Boylan" <Ro********@stanfordalumni.org> wrote in message
news:pa****************************@stanfordalumni .org...

I am trying to understand under what circumstances destructors get called
with std::vector. I have an application in which I will put real objects,
not just pointers, in the vector.

1. The standard says that empty() has constant complexity. If it actually
called the destructor for each object, it seems to me it would have
linear complexity. Does empty() call the destructor for each object in


the

container? If yes, why is it described as having constant commplexity?
If no, that seems like a problem too.



A conforming implementation of empty() is: return this->size() > 0;
This function does not empty the vector ( unlike clear() ): it only
returns a boolean that indicates whether the container is empty or not.



Josuttis in his book "The C++ standard library" recommends empty() over
container.size() > 0. He says it is _usually_ more efficient.
Given this implementation this might not be true.

2. The standard describes clear by saying that it behaves like
erase(begin, end). That seems as if it would erase the first element,


copying

all succedding elements over it, and so on, which is obviously very
inefficient. Is it safe to assume something more reasonable is happening
under the covers?


erase() does not remove elements one by one: the whole range is "removed"
by copying/moving the following elements over it. Then the unused trailing
elements are removed.
Say if the first three elements of ABCDEFGH are erased, steps that will
typically happen are:
DEFGH are copied down using the assignment operator --> DEFGHFGH
The trailing elements are destroyed --> DEFGH


hmm..IIRC, they are not.
One must take care to erase the trailing elements (i.e FGH).

Best wishes,
Sharad


这篇关于关于std库容器上的析构函数的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆