STL随机访问迭代器超出数组大小和自我实现迭代器

时间:2022-12-21 13:29:01

I got an assignment to implement a template array with an iterator and to overlad some operators of my iterator and I have a few questions. From what i understand the std random accessed iterator allows u to exceed the array. Does it allow to get the value it is holding over the Size? Does it allow the user to write over that memory?

我得到了一个使用迭代器实现模板数组的任务,并且覆盖了迭代器的一些操作符,我有几个问题。根据我的理解std随机访问迭代器允许你超过数组。它是否允许获得超过大小的值?它是否允许用户写入该内存?

And for my implementation, should i allow access over the Size? should i allow to get the data out of the Size? should i allow any change to it?

对于我的实现,我应该允许访问大小吗?我应该允许从大小中获取数据吗?我应该允许任何改变吗?

what is considered good programming in this case?

在这种情况下,什么被认为是好的编程?

any help will be much appreciated

任何帮助都感激不尽

5 个解决方案

#1


1  

I think you may be reading too much into your assignment, but your questions do bear consideration nonetheless.

我认为你可能会在你的作业中读得太多,但你的问题仍然需要考虑。

First of all, some considerations:

首先,一些考虑因素:

  • there are both mutating and non-mutating iterators (iterator and const_iterator nested types in general), the former allowing writing to the pointed-to element, and the latter not.
  • 有变异迭代器和非变异迭代器(通常是迭代器和const_iterator嵌套类型),前者允许写入指向元素,而后者不允许。

  • iterators are supposed to be lightweight, they are copied over and over in many algorithms
  • 迭代器应该是轻量级的,它们在许多算法中反复复制

Now, with regard to your questions, there is indeed a design decision on whether to perform bounds checking or not.

现在,关于你的问题,确实有一个关于是否进行边界检查的设计决定。

In general, iterators in C++ are so lightweight that they perform no bounds checking at all. This is the name of efficiency and the you don't pay for what you don't use philosophy. If the user ever overshoot... she will fall prey to Undefined Behavior, that is anything could happen.

通常,C ++中的迭代器非常轻量级,根本不执行边界检查。这是效率的名称,你不支付你不使用哲学的东西。如果用户过度使用......她将成为未定义行为的牺牲品,那就是任何事情都可能发生。

However, most (if not all) STL implementations will also acknowledge the issue and provide a debug mode (checked mode) that you can use when testing your application; of course those induce an additional cost, not only CPU-wise but also potentially memory-wise.

但是,大多数(如果不是全部)STL实现也会确认问题并提供可在测试应用程序时使用的调试模式(检查模式);当然,那些会产生额外的成本,不仅是CPU方面的,而且也可能是内存方面的。

As such, it is your own choice whether to provide checks, or not, and possibly to provide it optionally. I would recommend starting off without checks, and only tack them on later on as you have a better idea of what the system looks like.

因此,无论是否提供支票,您都可以自行选择,也可以选择提供支票。我建议出发没有检查,只钉他们以后你有什么样的系统,看起来像一个更好的主意。

#2


2  

The amount of runtime checking that iterators do is up to them. The std library iterators generally do very little runtime checking, as part of the design philosophy of the std library is to give near-hand-coded container performance with high level type checking.

迭代器执行的运行时检查量取决于它们。 std库迭代器通常只进行很少的运行时检查,因为std库的设计原则的一部分是通过高级类型检查提供近手编码的容器性能。

However, many std library implementations include multiple levels of runtime checking as an option for debug builds. This means that if you ask for the contents of an invalid iterator, the std iterator will invoke undefined behavior and probably give you the contents of some random memory past the end of the buffer, or sometimes segfault. And if you write, it will happily write to that memory that you aren't allowed to write to.

但是,许多std库实现包括多级运行时检查作为调试版本的选项。这意味着如果你要求无效迭代器的内容,std迭代器将调用未定义的行为,并可能在缓冲区末尾提供一些随机内存的内容,或者有时会提供段错误。如果你写,它会愉快地写入你不允许写入的内存。

As you are writing an iterator, it would be a good idea to include debugging tools within the iterator, because you won't write it correctly the first time. While std library iterator debugging tools are mainly about catching the user of the iterator making a mistake, the kind of checks you'll want to do to determine if the writer of the iterator is making a mistake (ie, you) would be similar.

在编写迭代器时,在迭代器中包含调试工具是个好主意,因为第一次不能正确编写它。虽然std库迭代器调试工具主要是关于捕获迭代器的用户犯错误,但是你想要做的检查是为了确定迭代器的编写者是否犯了错误(即你),这类似。

It would be good practice to both include, and to not include, such checks. And you should definitely include such checks (hooked up to an exception, assert, or even just an error logging system -- cerr counts as error logging in this context) when developing your iterators, even if the checks can be disabled or go away in "production" code.

包括但不包括此类检查是一种良好做法。在开发迭代器时,你肯定应该包括这样的检查(连接到异常,断言,甚至只是一个错误记录系统 - cerr在这个上下文中计为错误记录),即使检查可以被禁用或消失“生产”代码。

#3


1  

The size is not important for overflow. A random access iterator means that you can lookup an element with operator[] or increment or decrement by an arbitrary amount with operator += or + or -= or -

大小对于溢出并不重要。随机访问迭代器意味着您可以使用operator []查找元素,或使用operator + =或+或 - =或 - 增加或减少任意数量的元素

View all the operations needed here http://www.cplusplus.com/reference/iterator/RandomAccessIterator/

查看此处所需的所有操作http://www.cplusplus.com/reference/iterator/RandomAccessIterator/

#4


1  

In the Standard C++ Library (formerly known as STL) iterators do not perform range checking in the same way that in C pointers do not perform range checking. Accessing memory through an iterator pointing beyond the allocated bounds is undefined behavior, in the same way that accessing memory through a pointer that points beyond the allocated bounds is undefined behavior. You should follow the same principle in the design of your iterators, i.e. you should perform no bounds checks on data accesses.

在标准C ++库(以前称为STL)中,迭代器不执行范围检查,其方式与C指针不执行范围检查的方式相同。通过指向超出分配边界的迭代器访问内存是未定义的行为,与通过指向超出分配边界的指针访问内存的方式相同,是未定义的行为。您应该在迭代器的设计中遵循相同的原则,即您不应对数据访问执行边界检查。

#5


1  

From what i understand the std random accessed iterator allows u to exceed the array.

根据我的理解std随机访问迭代器允许你超过数组。

Not quite; you can't access anything outside the container, and trying to do so will give undefined behaviour. But the iterator is not required to prevent you from trying to access invalid memory.

不完全的;您无法访问容器外的任何内容,尝试这样做会产生未定义的行为。但是,迭代器不需要阻止您尝试访问无效内存。

The reason is that there could be a significant runtime cost to checking the range; by not requiring this, you can have the choice between a fast implementation that requires you to design your access patterns correctly, or a slow, safer implementation that can detect some mistakes for you.

原因是检查范围可能会产生大量的运行时成本;通过不要求这一点,您可以选择需要正确设计访问模式的快速实现,或者可以检测到某些错误的缓慢,更安全的实现。

Does it allow to get the value it is holding over the Size? Does it allow the user to write over that memory?

它是否允许获得超过大小的值?它是否允许用户写入该内存?

It might detect that and report an error; or it might not, and allow you to access invalid memory with undefined results.

它可能检测到并报告错误;或者它可能没有,并允许您访问具有未定义结果的无效内存。

And for my implementation, should i allow access over the Size?

对于我的实现,我应该允许访问大小吗?

No, it makes no sense to allow it. You can choose whether to actively prevent it by checking access at runtime, or to passively prevent it by documenting that it's the user's responsibility to make sure the iterator remains valid.

不,允许它是没有意义的。您可以通过在运行时检查访问权来选择是否主动阻止它,或者通过记录用户有责任确保迭代器保持有效来被动地阻止它。

what is considered good programming in this case?

在这种情况下,什么被认为是好的编程?

An unchecked iterator is simpler and doesn't add any, perhaps unwanted, performance costs. You could provide checked iterators as well; either separately or as wrappers around the unchecked ones, to give the user the choice of how fast or safe they want it.

未经检查的迭代器更简单,并且不会添加任何可能不需要的性能成本。您也可以提供已检查的迭代器;无论是单独的还是作为未经检查的包装器的包装器,都可以让用户选择他们想要的速度或安全性。

#1


1  

I think you may be reading too much into your assignment, but your questions do bear consideration nonetheless.

我认为你可能会在你的作业中读得太多,但你的问题仍然需要考虑。

First of all, some considerations:

首先,一些考虑因素:

  • there are both mutating and non-mutating iterators (iterator and const_iterator nested types in general), the former allowing writing to the pointed-to element, and the latter not.
  • 有变异迭代器和非变异迭代器(通常是迭代器和const_iterator嵌套类型),前者允许写入指向元素,而后者不允许。

  • iterators are supposed to be lightweight, they are copied over and over in many algorithms
  • 迭代器应该是轻量级的,它们在许多算法中反复复制

Now, with regard to your questions, there is indeed a design decision on whether to perform bounds checking or not.

现在,关于你的问题,确实有一个关于是否进行边界检查的设计决定。

In general, iterators in C++ are so lightweight that they perform no bounds checking at all. This is the name of efficiency and the you don't pay for what you don't use philosophy. If the user ever overshoot... she will fall prey to Undefined Behavior, that is anything could happen.

通常,C ++中的迭代器非常轻量级,根本不执行边界检查。这是效率的名称,你不支付你不使用哲学的东西。如果用户过度使用......她将成为未定义行为的牺牲品,那就是任何事情都可能发生。

However, most (if not all) STL implementations will also acknowledge the issue and provide a debug mode (checked mode) that you can use when testing your application; of course those induce an additional cost, not only CPU-wise but also potentially memory-wise.

但是,大多数(如果不是全部)STL实现也会确认问题并提供可在测试应用程序时使用的调试模式(检查模式);当然,那些会产生额外的成本,不仅是CPU方面的,而且也可能是内存方面的。

As such, it is your own choice whether to provide checks, or not, and possibly to provide it optionally. I would recommend starting off without checks, and only tack them on later on as you have a better idea of what the system looks like.

因此,无论是否提供支票,您都可以自行选择,也可以选择提供支票。我建议出发没有检查,只钉他们以后你有什么样的系统,看起来像一个更好的主意。

#2


2  

The amount of runtime checking that iterators do is up to them. The std library iterators generally do very little runtime checking, as part of the design philosophy of the std library is to give near-hand-coded container performance with high level type checking.

迭代器执行的运行时检查量取决于它们。 std库迭代器通常只进行很少的运行时检查,因为std库的设计原则的一部分是通过高级类型检查提供近手编码的容器性能。

However, many std library implementations include multiple levels of runtime checking as an option for debug builds. This means that if you ask for the contents of an invalid iterator, the std iterator will invoke undefined behavior and probably give you the contents of some random memory past the end of the buffer, or sometimes segfault. And if you write, it will happily write to that memory that you aren't allowed to write to.

但是,许多std库实现包括多级运行时检查作为调试版本的选项。这意味着如果你要求无效迭代器的内容,std迭代器将调用未定义的行为,并可能在缓冲区末尾提供一些随机内存的内容,或者有时会提供段错误。如果你写,它会愉快地写入你不允许写入的内存。

As you are writing an iterator, it would be a good idea to include debugging tools within the iterator, because you won't write it correctly the first time. While std library iterator debugging tools are mainly about catching the user of the iterator making a mistake, the kind of checks you'll want to do to determine if the writer of the iterator is making a mistake (ie, you) would be similar.

在编写迭代器时,在迭代器中包含调试工具是个好主意,因为第一次不能正确编写它。虽然std库迭代器调试工具主要是关于捕获迭代器的用户犯错误,但是你想要做的检查是为了确定迭代器的编写者是否犯了错误(即你),这类似。

It would be good practice to both include, and to not include, such checks. And you should definitely include such checks (hooked up to an exception, assert, or even just an error logging system -- cerr counts as error logging in this context) when developing your iterators, even if the checks can be disabled or go away in "production" code.

包括但不包括此类检查是一种良好做法。在开发迭代器时,你肯定应该包括这样的检查(连接到异常,断言,甚至只是一个错误记录系统 - cerr在这个上下文中计为错误记录),即使检查可以被禁用或消失“生产”代码。

#3


1  

The size is not important for overflow. A random access iterator means that you can lookup an element with operator[] or increment or decrement by an arbitrary amount with operator += or + or -= or -

大小对于溢出并不重要。随机访问迭代器意味着您可以使用operator []查找元素,或使用operator + =或+或 - =或 - 增加或减少任意数量的元素

View all the operations needed here http://www.cplusplus.com/reference/iterator/RandomAccessIterator/

查看此处所需的所有操作http://www.cplusplus.com/reference/iterator/RandomAccessIterator/

#4


1  

In the Standard C++ Library (formerly known as STL) iterators do not perform range checking in the same way that in C pointers do not perform range checking. Accessing memory through an iterator pointing beyond the allocated bounds is undefined behavior, in the same way that accessing memory through a pointer that points beyond the allocated bounds is undefined behavior. You should follow the same principle in the design of your iterators, i.e. you should perform no bounds checks on data accesses.

在标准C ++库(以前称为STL)中,迭代器不执行范围检查,其方式与C指针不执行范围检查的方式相同。通过指向超出分配边界的迭代器访问内存是未定义的行为,与通过指向超出分配边界的指针访问内存的方式相同,是未定义的行为。您应该在迭代器的设计中遵循相同的原则,即您不应对数据访问执行边界检查。

#5


1  

From what i understand the std random accessed iterator allows u to exceed the array.

根据我的理解std随机访问迭代器允许你超过数组。

Not quite; you can't access anything outside the container, and trying to do so will give undefined behaviour. But the iterator is not required to prevent you from trying to access invalid memory.

不完全的;您无法访问容器外的任何内容,尝试这样做会产生未定义的行为。但是,迭代器不需要阻止您尝试访问无效内存。

The reason is that there could be a significant runtime cost to checking the range; by not requiring this, you can have the choice between a fast implementation that requires you to design your access patterns correctly, or a slow, safer implementation that can detect some mistakes for you.

原因是检查范围可能会产生大量的运行时成本;通过不要求这一点,您可以选择需要正确设计访问模式的快速实现,或者可以检测到某些错误的缓慢,更安全的实现。

Does it allow to get the value it is holding over the Size? Does it allow the user to write over that memory?

它是否允许获得超过大小的值?它是否允许用户写入该内存?

It might detect that and report an error; or it might not, and allow you to access invalid memory with undefined results.

它可能检测到并报告错误;或者它可能没有,并允许您访问具有未定义结果的无效内存。

And for my implementation, should i allow access over the Size?

对于我的实现,我应该允许访问大小吗?

No, it makes no sense to allow it. You can choose whether to actively prevent it by checking access at runtime, or to passively prevent it by documenting that it's the user's responsibility to make sure the iterator remains valid.

不,允许它是没有意义的。您可以通过在运行时检查访问权来选择是否主动阻止它,或者通过记录用户有责任确保迭代器保持有效来被动地阻止它。

what is considered good programming in this case?

在这种情况下,什么被认为是好的编程?

An unchecked iterator is simpler and doesn't add any, perhaps unwanted, performance costs. You could provide checked iterators as well; either separately or as wrappers around the unchecked ones, to give the user the choice of how fast or safe they want it.

未经检查的迭代器更简单,并且不会添加任何可能不需要的性能成本。您也可以提供已检查的迭代器;无论是单独的还是作为未经检查的包装器的包装器,都可以让用户选择他们想要的速度或安全性。