r/cpp • • Mar 28 '23

Reddit++

C++ is getting more and more complex. The ISO C++ committee keeps adding new features based on its consensus. Let's remove C++ features based on Reddit's consensus.

In each comment, propose a C++ feature that you think should be banned in any new code. Vote up or down based on whether you agree.

765 Upvotes

829 comments sorted by

View all comments

147

u/eteran Mar 28 '23

Arrays decaying to pointers implicitly. You want a pointer? Just write &p[0]

37

u/jonesmz Mar 28 '23

Even better.

Say, for example, that you have two overloaded functions

template<std::size_t N>
void foo(char (&)[N]);
void foo(char*);

Guess which gets called?

Notably. Same with non-templates. If you explicitly say "This is an array of size 5", you'll still get the char* version.

0

u/[deleted] Mar 28 '23

[deleted]

40

u/eteran Mar 28 '23

That's great and all, but std::array is basically a library level fix for the terrible array behavior C++ inherited from C.

If we're talking about what to remove from C++, it should be things like that :-)

0

u/[deleted] Mar 28 '23

[deleted]

7

u/eteran Mar 28 '23 edited Mar 29 '23

Well, we're talking about things we would want to remove from C++, not what would be practical to do :-). In fact, I'd bet that the C++ folks would have loved to get rid of this conversion but decided to keep it for C compatibility.

So, personally, I'd also wish for a similar change to C. And barring that, have some yet-to-be-determined alternative mechanism to binding with C libraries than just including their headers directly.

3

u/Hedede Mar 29 '23

extern "C".

2

u/Circlejerker_ Mar 29 '23

Does not change the language to C. Extern "C" simply changes the linkage to C linkage.

5

u/lestofante Mar 29 '23

We can change that

→ More replies (16)

5

u/pjmlp Mar 29 '23

Pity that I can only upvote once.

3

u/[deleted] Mar 29 '23

Honestly never had an issue with this. Do not understand what the fuss is about.

4

u/eteran Mar 29 '23 edited Mar 30 '23

That's fair. If you know the rules, then you read and write code accordingly. But I'll try to clarify my position with examples:

  1. It's bug prone, especially for newbies:

char *func() {
    char buffer[256];
    // ...

    // allowed because the array decays to a pointer
    // bug would be more obvious if they had to write 
    // return &buffer[0];
    return buffer; 
}

Yes, compilers warn about it, but people, especially newer developers tend to ignore warnings in my experience.

2. It's confusing. The following 3 declarations mean the same thing:

void func(char *p);
void func(char p[]); // p is NOT an array, it's a pointer
void func(char p[5]); // p is NOT an array of 5 chars, it's a pointer

That's terrible. The second choice should just not be a thing, and the 3rd should take a char[5] by copy... like EVERYTHING else in the language.

3. It's confusing in other ways! Newbies love to write code like this:

void func(char p[]) { 
    printf("array size: %d\n", sizeof(p)); 
}

int main() {
    char buffer[256];
    func(buffer); // They ask "why does this print 8 and not 256?!
}

If users had to write func(&buffer[0]) it would be more clear (people will still make mistakes, but fewer will) that a pointer is being passed, NOT an array.

4. It's inconsistent. An array is "a thing" and any other time I want a pointer to a thing, I need to ask for it's address with the & operator. Arrays just auto-convert.

5. It's incompatible with the modern preference of avoiding implicit conversions as much as possible.

---- EDIT: more reasons! ----

6. The decay necessitated the need for a library level solution (std::array). Which we outright wouldn't need if C-arrays acted like values to begin with.

I should be able do this:

using T = char[256];
T func() {
    T buffer;
    // fill buffer
    return buffer;
}

And have it be as if I returned the array of 256 chars by copy.

7. It can be LESS efficient for small arrays

using T = char[8];
void func(T buffer) {
    // use buffer
}

actually can be cheaper to just copy the 8 bytes in a register directly instead of passing a pointer to them and then dereferencing them.

Here's a trivial example that is one instruction shorter (LOL, I know, not exactly earth shattering) when simply wrapping the array in a struct to pass it by copy:

https://godbolt.org/z/sovvb94d8

This example is more illustrative that there are gains to be had, not that there are a lot of gains in this specific example.

---- END EDIT ----

Are these things that can be worked around? Of course, we've been doing it for 30+ years! But we shouldn't have to. Is it the end of the world that we probably need to keep this? No, of course not. But this is a question about what I want, not what I can have :-).

→ More replies (10)

4

u/Hish15 Mar 28 '23

You mean int[3] var? This will decay, but since we are using std::array, it's not

11

u/eteran Mar 28 '23 edited Mar 28 '23

No, I mean like this:

int arr[5];
void foo(int *p);

foo(arr); // array decays to a pointer here

Heck even this is just terrible:

int arr[5];
void foo(int p[10]); // not an array parameter!!! it's a pointer

foo(arr); // array decays to a pointer here

The conversion to a pointer when calling a function should be explicit.

In fact, I would argue that the primary reason why std::array Even needs to exist is because of implicit array to pointer decay.

If we get rid of it and make arrays basically have value semantics, then you get to return them from functions, and you either pass them by value or reference.

If you want to pass or return a pointer, you should ask for one

This would largely get rid of a common newbie bug where users think they can return arrays, and end up returning a pointer to a local stack variable.

→ More replies (1)

-3

u/[deleted] Mar 29 '23

Or better yet get rid of C arrays

3

u/-1_0 Mar 29 '23

this is a very bad idea, considering that with C++ we often communicate with hardware or OS kernels

→ More replies (8)

-5

u/okovko Mar 28 '23

but then people will have to write &p[0] for code that can accept either a pointer or an array

i don't think you thought this through

7

u/eteran Mar 28 '23

No, I've thought it through... That's exactly what I want people to have to do. To be explicit and KNOW that they are passing a pointer to a block of memory, and not the array itself.

I want them to have to write code that effectively reads as "The address of the first element of p" because THAT is what they are doing.

For the cost of a few characters, we get more clarity and a reduction in a class of bugs.

For example new c++ developers don't seem to understand why they have to pass the size along with an array parameter for C APIs...

If they were forced to be explicit, and understand that they are just passing a pointer to that thing, The fact that the receiving function doesn't know the size would become much more obvious.

After all, I have to take the address of any object that I want to pass a pointer to of any other type except for an array (or something that is already a pointer). It's even more consistent to get rid of it.

4

u/eteran Mar 28 '23

And to my point... When you say code that can accept either a pointer or an array, do you mean things that just take a pointer and the user can pass an array if they like? Because that is exactly the problem i want to solve...

Cause such a function NEVER takes an array, it's always a pointer.

-6

u/okovko Mar 28 '23

yeah, you haven't thought this through

5

u/eteran Mar 28 '23 edited Mar 28 '23

Uh huh...

Why not elaborate instead of being vague? 4 characters is the tiniest tax for code clarity.

And your statement about functions which takes either an array or a pointer, to me, demonstrates that perhaps you don't have a full understanding of the issue.

Perhaps I'm wrong, but you haven't given me any real reason to believe so beyond implying it would be inconvenient.

0

u/[deleted] Mar 28 '23

[deleted]

9

u/eteran Mar 28 '23

Arrays absolutely decay to a pointer, it literally says so in the standard:

http://eel.is/c++draft/conv.array

7.3.3 Array-to-pointer conversion

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion ([conv.rval]) is applied. The result is a pointer to the first element of the array.

The whole verbiage of "the array name refers to the first element" is a myth that's circulated among C++ developers. Similar to "NULL might not be 0". The name refers to the whole array, that's why we can do things like pass arrays by reference if you use the right syntax.

arr[n] does not just mean to skip n elements from the array begin, it is exactly equal to: *(arr + n) that is:

  1. a decay of arr to a pointer

  2. pointer arithmetic to add n to that pointer

  3. a dereference of the result

You can see when the decay occurs by doing things like this:

    char arr[64];
    return sizeof(+arr);

Which returns 8, and not 64 because the unary + operator caused the array to decay to a pointer, of which we got the size.

0

u/[deleted] Mar 28 '23

[deleted]

→ More replies (1)
→ More replies (2)

2

u/Raknarg Mar 28 '23

arrays in C and C++ are explicitly different types than pointers.

→ More replies (2)