x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Office Holiday

Epic Games' offices will be on holiday from June 22nd to July 7th. During this period support will be limited. Our offices will reopen on Monday, July 8th. 

C++ TArray and ConstIterators

Here's a snippet from Array.h:

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 /** STL-like iterators to enable range-based for loop support. */
 #if PLATFORM_COMPILER_HAS_RANGED_FOR_LOOP

     FORCEINLINE TIterator begin()
     {
         return TIterator(*this);
     }

     FORCEINLINE TConstIterator begin() const
     {
         return TConstIterator(*this);
     }

     FORCEINLINE TIterator end()
     {
         return TIterator(*this, Num());
     }

     FORCEINLINE TConstIterator end() const
     {
         return TConstIterator(*this, Num());
     }

 #endif

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

How do you use TConstIterators?

Product Version: Not Selected
Tags:
more ▼

asked Mar 11 '14 at 02:33 AM in C++ Programming

avatar image

ue4-archive ♦♦ STAFF
49.9k 3665 1991 9118

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

Yes, you can. The difference is the const. For example, here is an ancient example:

 class FScriptArray : protected FHeapAllocator::ForAnyElementType
 {
 public:
     void* GetData()
     {
         return this->GetAllocation();
     }
     const void* GetData() const
     {
         return this->GetAllocation();
     }

This is used all over the place.

more ▼

answered Mar 11 '14 at 02:33 AM

avatar image

ue4-archive ♦♦ STAFF
49.9k 3665 1991 9118

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

No. const void* GetData() const now has a different signature (the final "const") and means that it can be called from other functions that are also const.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

I am missing something here. The two examples are completely analougous to my read.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

Okay, let's say that I have a function like this:

 void OCPlayerController::SelectActor( AActor * p_actor )
 {
         for(TArray< class UActorComponent* >::TConstIterator it = p_actor->Components.begin(); it != p_actor->Components.end(); ++it)
 {
     // Do something here
 }

...then you get:

 1> error C2440: 'initializing' : cannot convert from 'TIndexedContainerIterator' to 'TIndexedContainerIterator'
 1>          with
 1>          [
 1>              ContainerType=TArray,
 1>              ElementType=UActorComponent *,
 1>              IndexType=int32
 1>          ]
 1>          and
 1>          [
 1>              ContainerType=const TArray,
 1>              ElementType=UActorComponent *const ,
 1>              IndexType=int32
 1>          ]
 1>          No constructor could take the source type, or constructor overload resolution was ambiguous
 

But if I change the code to be:

 void OCPlayerController::SelectActor( AActor * p_actor )
 {
         for(TArray< class UActorComponent* >::TIterator it = p_actor->Components.begin(); it != p_actor->Components.end(); ++it)
 {
     // Do something here
 }

...then it compiles and works. Obviously this is because p_actor->Components is non-const. But I will always choose to use const over non-const except where I'm changing a value. Not allowing me to do so is dangerous! ;)

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

Anyway, the point I'm making is that I should be able to use const iterators from non-const functions. I shouldn't only be able to use const iterators on const objects.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

begin and end are for "ranged for loops". Use CreateIterator and CreateConstIterator instead. I will add steve to the ticket. He can talk about why the ranged for is set up that way.

Here is an example from the same file:

         for( auto It=Items.CreateConstIterator(); It; ++It )
 
avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

Ha! I tried to use CreateConstIterator() originally but it wasn't obvious how I was supposed to check that the iterator was still in bounds - which is why I ended up in the begin()...end() rabbit hole. :)

Which file is that example from?

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

Hi Neil,

Glad the confusion regarding the non-const/const member function has been sorted out. The code certainly isn't illegal, though it may be missing functionality... see below.

begin() and end() were added simply to support C++11's ranged-for syntax, that is:

 for (UActorComponent* Comp : p_actor->Components)
 {
     // Use Comp here
 }

Those functions are directly called by the language when this syntactic form is used. They weren't really intended to be used directly by developers, which has lead to the confusion.

The other part of the confusion is caused by the fact that our TIterators are not implicitly (nor explicitly, for that matter) convertible to their TConstIterator equivalent. This is what allows you to call .begin() on a non-const STL container and have it assigned to a const_iterator.

We could add support for that but, as I say, begin/end weren't really intended to be used directly. CreateIterator and CreateConstIterator are the intention here, as Gil has already mentioned. We could add those conversions to our iterators, but it would be for a workflow which we don't plan to support.

Hope this clears up the issue,

Steve

PS. Template arguments are also make up a function's signature, which means you can legally have functions defined as follows, which otherwise look like they only vary by return type:

template <typename T> T GetT();

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

Nope, it certainly wasn't illegal. I missed the const keyword which would, of course, change the signature. Gil was right - and that's why I changed the topic so that I wouldn't be misleading - and to lead people down the right path in future!

The problem currently is that a large majority of the code is undocumented. It's quite readable, kudos to Epic for that, but finding out how to get all of the sockets for a given actor sent me down a winding rabbit hole and ultimately led me to the TArray class.

I'm perfectly fine using TConstIterator and I appreciate the help from both Gil and yourself - I just hope that in future the headers can be better documented so I can see what exactly I'm meant to use in order to iterate over things such as a TArray. :)

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

It's a fair point, though it's likely that the sort of documentation you're after would be 'offline', i.e. not in the headers.

The ranged-for syntax support is relatively new, as it wasn't until recently (when we supported VC2012) that we had parity for this feature across our supported compilers. The problem with the STL-like naming is that people like yourself naturally assume that it's STL-like in its semantics, which it isn't, and it fails when you try to use it as such. But the readability and maintainability advantages of ranged-for syntax is too great to ignore.

However, I will add some comments to those begin/end functions which say they're not intended to be used directly.

Steve

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM

I see what Neil means. There's a big difference between, say, TArray and std::vector:

 TArray int_array;
 TArray::TIterator iter = int_array.begin();
 TArray::TConstIterator const_iter = int_array.begin();

 std::vector int_vec;
 std::vector::iterator vec_iter = int_vec.begin();
 std::vector::const_iterator vec_iter_const = int_vec.begin();

With std::vector, you can easily get the const_iterator from the non_const vector object, but with TArray, you get a compile error on the third line.

avatar image ue4-archive ♦♦ STAFF Mar 11 '14 at 02:33 AM +

... And you can certainly get around it by declaring another const& TArray and setting it equal to int_array and calling that on it, but you shouldn't have to.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question