0

I'm currently studying C++. Coming from Java, lots of stuff is really weird to me.

At some point I tried to create an array of a size that's determined at runtime, like so:

int size = functionCall(argument);
int array[size];

This compiled and ran, but gave really weird output later in the program.

Someone told me I have to do this:

int size = functionCall(argument);
int* array = new int[size];

Because new allows stuff to be dynamically allocated, i.e. if I understand correctly allocated according to something that's only known at runtime.

Two questions:

1- Is my understanding of new correct?

2- Why doesn't C++ allow the first version of my code?

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • possible duplicate of [How do you initialise a dynamic array in C++?](http://stackoverflow.com/questions/2029651/how-do-you-initialise-a-dynamic-array-in-c) – dandan78 Oct 02 '14 at 14:07
  • The first does not work because... well, because the syntax is incorrect. The syntax in different languages is different, and the syntax you used is not valid C++. – David Rodríguez - dribeas Oct 02 '14 at 14:09
  • @DavidRodríguez-dribeas Of course, but saying `int array[8]` *is* valid syntax, isn't it? – Aviv Cohn Oct 02 '14 at 14:09
  • @AvivCohn: Yes, but ... well, it´s just like it is. Don´t expect C++ to be similar to Java; problem solved. – deviantfan Oct 02 '14 at 14:11
  • I don't like questions which are edited totally changing the topic asked – Marco A. Oct 02 '14 at 14:11
  • 7
    Let me give you some simple advice: for now (like, the next year or two) forget that C++ has/uses/supports `new` at all. The use you're making of it here, and nearly any other use you might make of it any time soon, is just "Java hangover", and even if you don't feel the headaches yet, that's what you're creating. For your current problem, look up `std::vector`. – Jerry Coffin Oct 02 '14 at 14:13
  • @AvivCohn: `int array[8]` is valid syntax, `int array[variable]` is not. – David Rodríguez - dribeas Oct 02 '14 at 14:15
  • @DavidRodríguez-dribeas well, `int array[variable]` is also valid syntax. In C++ many things can be made valid syntax if you know which buttons to push. – R. Martinho Fernandes Oct 02 '14 at 14:16
  • @JerryCoffin that is 2 years of deferring what should be known at the start. – Preet Kukreti Oct 02 '14 at 14:18
  • @PreetKukreti you seem to have misread. Jerry didn't suggest deferring `std::vector`. – R. Martinho Fernandes Oct 02 '14 at 14:19
  • 2
    @PreetKukreti: No, it is not. `new` is not something a C++ programmer needs to know at (or even close to) "the start". – Jerry Coffin Oct 02 '14 at 14:20
  • @PreetKukreti No, it's advanced knowledge that's only useful for implementing very low-level bits, and a bad practice for everything else. – Cat Plus Plus Oct 02 '14 at 14:20
  • @R.MartinhoFernandes: `int array[variable]` as a declaration of `array`... what button do you need to push to make that happen? :) – David Rodríguez - dribeas Oct 02 '14 at 14:22
  • @DavidRodríguez-dribeas `const int variable = 1;`? – R. Martinho Fernandes Oct 02 '14 at 14:22
  • Its not advanced knowledge at all. There has been a new wave of propaganda for modern C++ that is trying to sell c++11 to java etc programmers that dictates this. Frankly, in some situations if you follow this, you are often paying for things you dont need. There are many situations where you can use static arrays + pointers instead of heap memory. I completely understand the DRY and RAII / safety issues that modern C++ solves. this is orthogonal to what I am saying. – Preet Kukreti Oct 02 '14 at 14:23
  • Also, what happens when said new programmer encounters any legacy code. – Preet Kukreti Oct 02 '14 at 14:24
  • @R.MartinhoFernandes: Hardly a *variable* is it not? Oh, my, should I have made more explicit that `variable` is *variable* (i.e. can be changed?) – David Rodríguez - dribeas Oct 02 '14 at 14:24
  • 6
    @PreetKukreti: "static arrays + pointers" wouldn't involve `new`, now would it? A complete beginner (in nearly any language) shouldn't be dealing with legacy code. Depending on the code in question, he might also need to deal with SFINAE, CRTP, etc., but that doesn't mean somebody should learn them immediately either. – Jerry Coffin Oct 02 '14 at 14:27
  • @PreetKukreti you should not be looking at legacy code if you are not experience with that language. Using std::vector is the correct solution, you have to start throwing awkward constraints at the problem before you start considering foolishly risky manual memory management. – thecoshman Oct 02 '14 at 14:28
  • @PreetKukreti: *static array and pointers*, enter multithreading... oh, wait cannot. *Legacy code*, correct, now the question is, do you want to teach people to write *legacy code*? Clearly the question is not about encountering that construct and wanting to understand it, but rather creating, and at this point I would not suggest to use a pointer and `new` in this case. A `vector` provides a safer alternative. *In some situations if you follow this, you are paying for things you don't need*... – David Rodríguez - dribeas Oct 02 '14 at 14:28
  • 7
    @PreetKukreti if you think preferring `std::vector` is a C++11 thing or a "modern C++" thing you are at least 13 years late to this game. This is more like "classical C++", as opposed to "pre-historical C++" which is the one where you're supposed to use `new` everywhere. – R. Martinho Fernandes Oct 02 '14 at 14:31
  • [...] In this case you will pay for two additional pointers in memory. If you don't use a `vector` you might end up paying more than that in memory leaks, time debugging and cluttering the business logic with low level constructs. A bit better would be `unique_ptr p ...`, which lifts some of the boilerplate, but then you need to explain and remember the `[]`, or you end up with undefined behavior... what were you going to gain, *two pointers*? – David Rodríguez - dribeas Oct 02 '14 at 14:32
  • My key point is that there are multiple ways of doing something. `std::vector` is indispensable. It's not all you need to know though. If you *ever* read anything even mildly performance oriented, I'm afraid you will need to venture outside of safe STL territory. I cannot believe the level of cargo cult here. There is a huge difference between knowing to use a `std::vector` and knowing `why` it is used and `how` it works; the latter points being incredibly important for anything past introductory coding (and more importantly, code reading). – Preet Kukreti Oct 02 '14 at 14:47
  • Also, before when I said static arrays, what I really meant to say at the time was plain C arrays whose size is known at compile time (statically), since a lot of people tend to use std::vectors even when the size is known and fixed at compile time. – Preet Kukreti Oct 02 '14 at 15:11
  • @R.MartinhoFernandes My point was not about std::vector being "modern" at all. It was about the attitude of hiding that operations like `new` and `delete` even exist that seems to be so prevalent today. It is one thing to discourage it (which i generally agree with), but its an entirely different thing to effectively censor it. – Preet Kukreti Oct 02 '14 at 15:26
  • 1
    @JerryCoffin -" (like, the next year or two) forget that C++ has/uses/supports new at all" - wow, that's really bad advice. Not everyone gets to live completely in the bubble that is C++11. Plenty of people have to go out there and enhance/maintain existing code that uses `new` all over the place. – Sean Oct 02 '14 at 16:32
  • @Sean: As already noted, rank beginners shouldn't be maintaining existing code, they should be learning. As also already noted, `std::vector` has been around a *long* time--it's certainly not something that was just added in C++11. Your conclusion is not supported by the "evidence" (using the term loosely) that you cite. – Jerry Coffin Oct 02 '14 at 16:36
  • 1
    @JerryCoffin The problem with your assertion is that a beginner can distinguish between "modern" code/advice/tutorials and "legacy" variants. AFAIC, all newbies should know the fundamentals, as well as the modern idioms, and why they are preferred. Today, most C++ jobs you land in the real world will involve reading, understanding and maintaining "non-modern" C++, so your point is not practical – Preet Kukreti Oct 02 '14 at 16:39
  • 1
    @Sean: I learnt to use STL containers, and avoid hand-juggled pointers, about twenty years ago. RAII was idiomatic long, long before C++11. While there is indeed plenty of dreadful code around, which many of us have to deal with from time to time, a beginner should first and foremost learn to write code well. – Mike Seymour Oct 02 '14 at 17:29
  • @MikeSeymour - that's great for you Mike, but there's probably plenty of code out there you didn't write, and it's going to have calls to new and delete. I never suggested that a beginner shouldn't learn to write code well, but it's important to learn how new/delete work from the outset. – Sean Oct 02 '14 at 18:44
  • @JerryCoffin - it's easy to say that rank beginners should be maintaining existing code, and whilst I agree in theory, in practice people often end up having to do so. If you took the time to read my comment you'd see that I stated your advice on ignoring new/delete for 2 years was bad, I never said anything about `std::vector`. – Sean Oct 02 '14 at 18:47
  • @PreetKukreti: And where did this "legacy" come from? Unless it's several decades old, then it came from people following advice like yours, and learning to write code the wrong way first. By learning *first* how to do it the right way, and *later* (if necessary) how to deal with low-level memory juggling and other dark corners of the language, you do a service not just to yourself (by knowing how to produce good code, not just maintain someone's "legacy"), but to the next generation (by not leaving them a "legacy" to maintain). – Mike Seymour Oct 02 '14 at 19:47
  • @MikeSeymour ...and this is the thing. I didn't give any advice or recommendation, I only gave an explanation. Also, to the others, I never said that `std::vector` is "modern". My mention of "modern" was more alluding the approach of shying away from talking about manual memory management entirely **(in the context of instruction/education)**. Just because I say it is useful to know about it, it does not mean I am endorsing it. There is a world of difference there. – Preet Kukreti Oct 03 '14 at 10:20

3 Answers3

8

At some point I tried to create an array of a size that's determined at runtime, like so: This compiled and ran, but gave really weird output later in the program.

What you created was a non-standard extension called VLA (A.K.A. Variable-length Array). It should have worked, really, but since it didn't I assume something went wrong on your end.

Because new allows stuff to be dynamically allocated, i.e. if I understand correctly allocated according to something that's only known at runtime.

Yes, your intuition is correct.

1- Is my understanding of new correct?

Yes. You use new to dynamically allocate memory. But that opens another can of worms.

2- Why doesn't C++ allow the first version of my code?

The C++ standard just doesn't support VLAs. I feel like the reasoning for this is outside the scope of the question.

In either case, if you wanted a dynamic array based on a runtime variable in C++ we tend to use std::vector. You code would then end up being this:

std::size_t size = get_size();
std::vector<int> arr(size);

Now you could use the std::vector as if it was a regular C array. The benefits of using std::vector over raw new is that it relieves you of the burden of using delete[] and it also provides strong exception safety when faced with exceptions before you get to the line that calls delete[].

sbi
  • 219,715
  • 46
  • 258
  • 445
Rapptz
  • 20,807
  • 5
  • 72
  • 86
2

C++ (unlike modern C) does not allow you to initialize an array using a value that is computed at run-time. It is possible to do

int x[size];

in C++, but the value contained within size must be known by the compiler. Therefore, the following is legal

int const size = 10; // Known at compile-time
int x[size];

But the following is not

int size;
cin >> size; // we only know size at run-time
int x[size]; // ERROR!

The reason for this is restriction is technical and I won't go into it here since you're clearly new to the language. Just know that if you want to declare an array (without using the keyword new) you need to know the size of it at compile-time.

As an alternative, you should check out the container std::vector, which allows you to safely allocate an array dynamically, without having to use new and delete.

std::vector<int> xs(10); // allocate space for ten ints.

The benefit is that, due to vector's destructor, you don't have to worry about managing the memory it allocates, thus leading to safer code.

So, in summary:

  1. Yes, your understanding of new is correct. If you only know the size at run-time, you need dynamic memory. However, avoid using new if at all possible: prefer vector.
  2. C++ simply does not allow arrays to have sizes known at run-time. All arrays created on the stack must have their sizes known at compile-time. This is different than in C, where such a thing is allowed.
bstamour
  • 7,746
  • 1
  • 26
  • 39
1
int size = functionCall(argument);
int* x = new int[size];

size is not known at compile time. it is known only at runtime. So you need to use heap allocation for your array. There is no way for the compiler to know what size this array should be at compile time, so it has to ask the heap memory allocator at run time to allocate enough space when it knows what size is. The new keyword is a request for heap memory.

if you did

static const int size = <constexpression>
int x[size];

for example if constexpression was 3 (a size_t convertible literal) or anything that was known at compile time, then it would use stack allocation, since the compiler would know at compile time how big the array should be and you would be allowed to do that.

If you want to create a contiguous array of ints who's size is only known at runtime, you should use std::vector which provides a safe wrapper around an array that can be dynamically resized at runtime:

std::vector<int> x(size);

If you know the size at compile time, you might even consider using std::array since it has a static size() method that does not take any extra storage and means you dont need to pass around a size as well (however it causes you instantiation cost at compile time per unique size):

std::array<int, size> x; // where size is known at compile time
Preet Kukreti
  • 8,417
  • 28
  • 36
  • downvoters please explain how the answer could be improved or what is wrong – Preet Kukreti Oct 02 '14 at 14:16
  • 1
    I gave answer quite similar to yours and it was also downvoted. I finally deleted it: I must be missing something... – Pablo Francisco Pérez Hidalgo Oct 02 '14 at 14:19
  • The something you are all missing is `std::vector`. – R. Martinho Fernandes Oct 02 '14 at 14:21
  • I think its either language lawyers or someone is trying to spread bad vibes. I'm curious to know what caused such a strong downvote streak – Preet Kukreti Oct 02 '14 at 14:21
  • Well, that and the mythical, irrelevant, stack vs heap distinction. – R. Martinho Fernandes Oct 02 '14 at 14:22
  • @R.MartinhoFernandes From Wikipedia: The Standard Template Library (STL) is a software library for the C++ programming language that influenced many parts of the C++ Standard Library. It provides four components called algorithms, containers, functional, and iterators. Yeah I would use a `std::vector` but what if you are unable to include anything in your code? – Pablo Francisco Pérez Hidalgo Oct 02 '14 at 14:24
  • What has that got to do with anything? The question was about dynamically sized arrays, the only right answer is std::vector. Stop spreading bad code. – thecoshman Oct 02 '14 at 14:25
  • Why would you be "unable to include anything in your code"? – Lightness Races in Orbit Oct 02 '14 at 14:26
  • @PabloFranciscoPérezHidalgo I have no idea what that is supposed to mean. From the *Standard For Programming Language C++*: " In addition to the facilities provided by C, C ++ provides additional data types, classes, templates, exceptions, namespaces, operator overloading, function name overloading, references, free store management operators, and additional library facilities." – R. Martinho Fernandes Oct 02 '14 at 14:27
  • 5
    You got a "strong downvote streak" for giving poor advice. Nothing more, nothing less. – Lightness Races in Orbit Oct 02 '14 at 14:27
  • @LightnessRacesinOrbit Understood – Pablo Francisco Pérez Hidalgo Oct 02 '14 at 14:29
  • 4
    Was the question edited previously? The question, as it is right now, just asks if his understanding of new is correct and why that is invalid C++. I don't understand why people were downvoted for not mentioning vector, even though they answered the question fine... – bstamour Oct 02 '14 at 14:32
  • yeah i put array instead of vector. due to the downvote streak. its making my brain malfunction. ill just leave now. might take a while till i crawl back to SO... gg. – Preet Kukreti Oct 02 '14 at 14:32