Jump to content
  • entries
  • comments
  • views

[C++] ArrayView-class

Sign in to follow this  


So I've been quite busy with refactoring the rendering and other systems of the engine for the last few months, and once I'm done I'll make some more entries for the graphical render-system.

Today I've been wondering if there is no cleaner solution to having to pass an arbitrary array to a function. I generally tend to fully qualify the container in such a case, but thats not always possible (and quite frankly not the flexible). What I'm talking about is a case like that:DrawItem* Compile(const StateGroup* pGroups, size_t numGroups);{ for(size_t i = 0; i < numGroups; i++) // no range-based for loops eigther :( { }}
Having to pass in the pointer and size separately to the function seems unsafe, C-esque and redundant to me. Not being able to use range-based for-loops is a minor annoyance. But there is no other native way, if I potentially want to support any source of array (raw fixed-size array, std::vector, std::array, dynamic allocation, ...).

So I came up with what I call an ArrayView-class. What it does and how it works is actually quite simple, which makes me wonder why I havn't seen anybody else come up with something like that:DrawItem* Compile(ArrayView groups){ for(const auto& group : groups) { }}
Yeah, thats the gist of it. I'm using a templated class to pass a view to an array, with a known size. The cool thing is, now it doesn't matter where this array comes from:void printArray(ArrayView view){ for(const int value : view) { std::cout << value; } std::cout << std::endl << std::endl;}void main(void){ std::vector vector = {1, 2, 3, 4, 5}; std::array array = { 1, 2, 3, 4, 5 }; int raw[] = { 1, 2, 3, 4, 5 }; int* pDynamic = new int[5] { 1, 2, 3, 4, 5}; const auto vectorView = makeArrayView(vector); const auto arrayView = makeArrayView(array); const auto rawView = makeArrayView(raw); const auto iteratorView = makeArrayView(vector.begin() + 2, vector.begin() + 4); const auto pointerView = makeArrayView(raw + 1, raw + 3); const auto dynamicView = makeArrayView(pDynamic, 5); const ArrayView* views[] = { &vectorView, &arrayView, &rawView, &iteratorView, &pointerView, &dynamicView, }; for(const auto pView : views) { printArray(*pView); } }
You can construct it from std::vector, std::array, compile-time arrays, even random-access iterators (probably a tad unsafe), and a raw-range of pointers (even more unsafe, but meh).


So... any reasons nobody has come up with something like that yet? Is the problem I'm trying to solve so uncommon/unimportant that nobody cared? Or are people still wary of using templates?
For me, I think I've spent my ~hour to write this quite well, as this will probably kill my conditioning to just put "vector" everywhere, even when I could just pass in a regular array. :D

For those of you interested in using this or trying it out, I've attached the header-file, alongside a visual-studio natvis-file. Requires C++11 (VS2015 or higher), and you'll have to replace the AE_ASSERTS with your own assert-macro, if you use one. This is the first iteration just after writing it, so there's probably still lots of stuff missing, but I consider it useable :)

Sign in to follow this  


Recommended Comments

As mentioned above, this is pretty much exactly what gsl::span does. In addition to this gsl also provides string_span and multi_span. If you haven't played around yet with gsl, I definitely suggest you give it a try. It's been incredibly useful for us so far.




I also remember seeing a Microsoft implementation of array_view, and am quite sure that an implementation of array_view was suggested for an upcoming C++ standard. I also believe that boost provides a similar implementation.

Share this comment

Link to comment

Ah, I didn't know about GSL. span seems to be exactly what I've done, just with lots more features (and probably more robust).


Microsofts array_view seems to take <T, Size>-parameters, and is thus unfit for my use-case. Seems to be more about some data as an array, which is something I've seen people ask for while researching this, too.

I've read the array_view proposal, but just from skimming over the proposal & source, I couldn't tell if it does the same as I wanted to have.

Share this comment

Link to comment
DrawItem* Compile(ArrayView<const StateGroup> groups)
    for(const auto& group : groups)


DrawItem* Compile(const ArrayView<const StateGroup> &groups)
    for(const auto& group : groups)

you do not want to copy an array everytime you pass it , not referencing copies the array

Share this comment

Link to comment

The ArrayView doesn't store the array, just a pointer+size. So not referecing copies exaclty 8 byte (12 on 64 bit), the same if you passed pointer+size separately.


Copying such small structs is usually equally fast, if not faster, then passing by reference, especially when the entire function argument list still fits into registers. It could even help with aliasing (MSVC is especially bad it this), and letting the compiler know that the value of the ArrayView won't change during this function call.


I usually just pass every struct <= 8, sometimes even 16 byte by value, unless the argument list gets too long (in which case one should probably just create an Args-struct anyways).

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!