dgnuff
dgnuff

Reputation: 3557

Why does std::array not have an operator T*?

With C arrays, it's been the case that simply naming an array has the same effect as writing &foo[0] for something approaching 50 years.

When converting from C style arrays to std::array<> in a project I'm working on, the vast majority of "error"s that appeared were due to the above property of C arrays.

In all cases, the solution was trivial, just append .data(). However it occurred to me that a carefully crafted operator T* ought to directly solve this issue.

Is there any technical reason this operator could not be created?

Upvotes: 0

Views: 295

Answers (4)

Nicol Bolas
Nicol Bolas

Reputation: 474196

C-style arrays are sized constructs. You can get the compile-time size of an array via various means. However, when the array decays into a pointer, you lose that compile-time sizing information. Even if the parameter is an "array" type, it's really still just a pointer with no size info. You can use template programming to preserve the size if the array is passed as a function parameter (template<size_t S> void func(T(&param)[S])), but that's it.

This implicit decaying of an array to a pointer is considered by many C++ programmers to be a design flaw in C-style arrays. Indeed, it would hardly be unreasonable to say that lossy conversions are probably not ones which should be implicit. Given that std::array is an attempt to fix as many of the flaws of C-style arrays as possible, allowing it to implicitly decay into a pointer would be counter-productive.

By contrast, C++20's std::span type provides an implicit conversion from a std::array (and C-style arrays, among others). The reason being that such a conversion preserves the information: pointer as well as size. Indeed, the conversion can even preserve the compile-time nature of that size.


Is there any technical reason this operator could not be created?

"Could not"? No.

Upvotes: 5

PaulMcKenzie
PaulMcKenzie

Reputation: 35454

Is there any good reason this operator doesn't exist?

If you mean why there is no operator T*() to automatically provide the cast, one (of multiple) potential reasons is exactly that -- the idea of automatic casting.

Maybe it would be convenient to have the code using std::array to just compile correctly by utilizing operator T*(), and away you go with a program that has been built with no errors. However there are some implications to this:

1) The call to operator T*() is a potential runtime cost that the programmer may not have desired, but just comes along for the ride. In C++, the goal is to only pay for what is desired, and having casting operators just impose themselves goes against this idea.

2) operator T*() and casting operators in general can potentially hide bugs or bottlenecks in running code, due to usage that the programmer is not aware of.

In my experience, ask a programmer that has a code base littered with casting operators what functions are actually being called, and more times than not, they are not sure what path their code is taking, or they are just plain wrong (and don't realize it until they partake in a debugging session and see all the twists and turns being done by the seemingly innocent casting operators being invoked).

Thus it is deemed far safer for the programmer to explicitly want to "convert" the data by calling a function such as data(), and not by utilizing a operator T*() they may not have been aware of.

Upvotes: 0

ivan.ukr
ivan.ukr

Reputation: 3561

data() is introduced to have similar interface across multiple STL containers. For example, std::string and std::vector also provide data() which gives address of actual data buffer. So std::array interface was designed to match that. Operator() that you suggest is quite different way, and doesn't seem to be absolutely appropriate. As above commenters also mentioned, the more appropriate is operator T*(), but still this is not how STL designers preferred to do - they introduced data(). Why? Maybe because it is just more readable.

Upvotes: 1

johannes
johannes

Reputation: 15989

Calling data() is a thing you should avoid. It can be useful to have this power for (as in our case migrating code or optimized code processing the guts) however it goes against the safety net std::array provides.

 std::array<int, 2> a{1,2};
 auto* ptr = a.data();
 std::cout << ptr[2]; // boom

Things taking away a safety net should be explicit.

Upvotes: -2

Related Questions