简体   繁体   English

我应该返回一个迭代器或一个指向STL容器中元素的指针吗?

[英]Should I return an iterator or a pointer to an element in a STL container?

I am developing an engine for porting existing code to a different platform. 我正在开发一个引擎,用于将现有代码移植到不同的平台。 The existing code has been developed using a third party API, and my engine will redefine those third party API functions in terms of my new platform. 现有代码是使用第三方API开发的,我的引擎将根据我的新平台重新定义这些第三方API函数。

The following definitions come from the API: 以下定义来自API:

typedef unsigned long shape_handle;    
shape_handle make_new_shape( int type );

I need to redefine make_new_shape and I have the option to redefine shape_handle . 我需要重新定义make_new_shape ,我可以选择重新定义shape_handle

I have defined this structure ( simplified ): 我已经定义了这个结构(简化):

struct Shape
{
    int type
};

The Caller of make_new_shape doesn't care about the underlying structure of Shape , it just needs a "handle" to it so that it can call functions like: make_new_shape的调用者不关心Shape的底层结构,只需要一个“句柄”就可以调用以下函数:

void `set_shape_color( myshape, RED );`

where myshape is the handle to the shape. 其中myshape是形状的句柄。

My engine will manage the memory for the Shape objects and other requirements dictate that the engine should be storing Shape objects in a list or other iterable container. 我的引擎将管理Shape对象的内存,并且其他要求规定引擎应该将Shape对象存储在列表或其他可迭代容器中。

My question is, what is the safest way to represent this handle - if the Shape itself is going to be stored in a std::list - an iterator, a pointer, an index? 我的问题是,表示此句柄最安全的方法是什么 - 如果Shape本身将存储在std :: list中 - 迭代器,指针,索引?

Both an iterators or a pointers will do bad stuff if you try to access them after the object has been deleted so neither is intrinsically safer. 如果在删除对象后尝试访问它们,那么迭代器或指针都会做坏事,所以它们本身都不安全。 The advantage of an iterator is that it can be used to access other members of your collection. 迭代器的优点是它可以用于访问集合的其他成员。

So, if you just want to access your Shape then a pointer will be simplest. 所以,如果你只是想访问你的Shape,那么指针将是最简单的。 If you want to iterate through your list then use an iterator. 如果要遍历列表,请使用迭代器。

An index is useless in a list since std::list does not overload the [] operator. 索引在列表中是无用的,因为std :: list不会使[]运算符重载。

IIF the internal representation will be a list of Shapes, then pointers and iterators are safe. IIF内部表示将是一个Shapes列表,然后指针和迭代器是安全的。 Once an element is allocated, no relocation will ever occur. 分配元素后,不会发生重定位。 I wouldn't recommend an index for obvious access performance reasons. 我不建议使用索引来明显访问性能。 O(n) in case of lists. 列表中的O(n)。

If you were using a vector, then don't use iterators or pointers, because elements can be relocated when you exceed the vectors capacity, and your pointers/iterators would become invalid. 如果使用向量,则不要使用迭代器或指针,因为当超过向量容量时可以重新定位元素,并且指针/迭代器将变为无效。

If you want a representation that is safe regardless of the internal container, then create a container (list/vector) of pointers to your shapes, and return the shape pointer to your client. 如果您想要一个安全的表示而不管内部容器,那么创建一个指向您的形状的指针的容器(列表/向量),并将形状指针返回给您的客户端。 Even if the container is moved around in memory, the Shape objects will stay in the same location. 即使容器在内存中移动,Shape对象也将保留在同一位置。

The answer depends on your representation: 答案取决于你的代表:

  • for std::list , use an iterator (not a pointer), because an iterator allows you to remove the element without walking the whole list. 对于std::list ,使用iterator (而不是指针),因为iterator允许您删除元素而不会遍历整个列表。
  • for std::map or boost::unordered_map , use the Key (of course) 对于std::mapboost::unordered_map ,使用Key (当然)

Your design would be much strong if you used an associative container, because associative containers give you the ability to query for the presence of the object, rather than invoking Undefined Behavior. 如果使用关联容器,您的设计会非常强大,因为关联容器使您能够查询对象的存在,而不是调用未定义的行为。

Try benchmarking both map and unordered_map to see which one is faster in your case :) 尝试对mapunordered_map进行基准测试,看看你的情况哪一个更快:)

Iterators aren't safer than pointers, but they have much better diagnostics than raw pointers if you're using a checked STL implementation! 迭代器并不比指针更安全,但如果您使用的是检查STL实现比原始指针更好的诊断!

For example, in a debug build, if you return a pointer to a list element, then erase that list element, you have a dangling pointer. 例如,在调试版本中,如果返回指向列表元素的指针,然后擦除该列表元素,则会有一个悬空指针。 If you access it you get a crash and all you can see is junk data. 如果你访问它就会崩溃,所有你能看到的就是垃圾数据。 That can make it difficult to work out what went wrong. 这可能很难弄清楚出了什么问题。

If you use an iterator and you have a checked STL implementation, as soon as you access the iterator to an erased element, you get a message something like "iterator was invalidated". 如果你使用迭代器并且你有一个经过检查的STL实现,只要你访问一个擦除元素的迭代器,就会得到类似“迭代器被无效”的消息。 That's because you erased the element it points to. 那是因为你删除了它指向的元素。 Boom, you just saved yourself potentially a whole lot of debugging effort. Boom,你刚刚为自己节省了大量的调试工作。

So, not indices for O(n) performance. 因此,不是O(n)性能的指标。 Between pointers and iterators - always iterators! 在指针和迭代器之间 - 总是迭代器!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM