4

I found some great "Heap vs Stack" questions and answers regarding the objects and STLs. (c++ arguments heap-vs-stack) (Please, let me know if STL objects such as vector or queue etc. behaves differently from custom class objects.)

While working on one of the programming contest problem, it occurred to me that arrays of primitive type are also passed as reference instead of manual copy(e.g., f(bool boo[10][10]) ).

I worked around this by having local array of primitive type and copying the parameter into the local array.

bool local_boo[10][10]; 
memcpy(local_boo, boo, sizeof(bool) * 10 * 10);

Also, it is safe to assume that I will only attempt to have individual copies of boo per function call when the size of the array of primitive type is known and fixed.

Here are my questions.

1) Is there a better way?

2) Does anyone know of any good reference that specifically targets whether an argument will be passed through Heap or Stack during the function calls?

3) Is there a better way to determine whether something is declared on Heap or Stack other than printing the address of the variable and determine by inspecting the address?

Thank you.

yjsoh
  • 87
  • 5
  • 4
    All argument are passed by value on the stack. Objects (variables) are on the stack unless allocated with new, malloc etc. Compound objects can complicate this simple picture if they contain pointers. – Richard Critten May 28 '18 at 08:58
  • 3
    Arrays are not passed by reference (they're passed as a pointer to their first element), and arguments are never passed on "the heap". – molbdnilo May 28 '18 at 08:59
  • And it's extremely rare to need to care about what area of memory an object resides in. – molbdnilo May 28 '18 at 09:08
  • Arguments are passed either by value or by reference. Only raw arrays decay to a pointer, so only the pointer is passed by value, pointing to the original array. If you use `std::array` instead then it will be passed by value. – rustyx May 28 '18 at 09:09
  • 1
    Arrays are special, but the C guys have figured out how to pass a copy anyway: [Why declare a struct than only contains an array in C?](https://stackoverflow.com/questions/6966570/why-declare-a-struct-that-only-contains-an-array-in-c) – Bo Persson May 28 '18 at 09:12
  • 2
    What is the problem you are trying to solve? Also function arguments are always automatic variables (aka. "stack"). You sound like you are mixed up between storage durations, and parameter passing methods – M.M May 28 '18 at 09:18
  • When working with primitive data types and you need to keep the dimensions variable, it might be better to write the code in C with VLA. Otherwise in C++, you'd use std::array and pass by ref. – Lundin May 28 '18 at 09:28
  • 1
    @molbdnilo There's a whole world out there beyond PC programming. Embedded systems programmers care where variables are stored every day. But then of course they normally don't use C++ to begin with. – Lundin May 28 '18 at 09:30
  • There 5 memory zone in C++, not just heap and stack. Here are some very good reading [answers](https://stackoverflow.com/questions/1169858/global-memory-management-in-c-in-stack-or-heap) and a great [article](http://cs-fundamentals.com/c-programming/memory-layout-of-c-program-code-data-segments.php) on the subject. – Clonk May 28 '18 at 12:24

4 Answers4

5

2) Does anyone know of any good reference that specifically targets whether an argument will be passed through Heap or Stack during the function calls?

The call stack is not mentioned in the C++ standard (it is an implementation detail; check by reading n3337 or some more recent standard). The calling conventions are specific to some implementation, so study the ABI for your system. Automatic variables might not sit on the stack (e.g. they could be only in registers, or disappear entirely at compilation time).

On x86-64 most ABIs (see this) define that the first few (generally 6) arguments, when they are "scalar", are passed thru registers (and details, such as type of arguments, matter a lot: a floating point value is not passed the same way as an integer). Also, plain structures of two scalar components, when they are returned, get passed in two registers in most of those ABIs.

Also, most C++ compilers are in practice optimizing compilers, and they can (and do) compile calls differently (for example, they often do some function inlining - even without any inline annotation), so the passing of arguments is really implementation specific (and could vary from one call site to another of the same called function).

However, raw arrays decay into pointers. Read also about plain old data.

You might think of "argument passed on the heap" (but that is a simplification, not the real thing) if some copy constructor is involved which passes some data thru heap-allocated memory. Read also about the rule of five and about RAII.

In some cases, an optimizing compiler is allowed, per the as-if rule, to replace some internal heap allocation by something else (including some "stack allocation").

Basile Starynkevitch
  • 1
  • 16
  • 251
  • 479
2

Not related to the question, but the name STL has been deprecated for years, the correct name is Standard C++ library.

Next for how objects are passed to functions, you should be aware that arrays are not first class elements in C++. Since C++ 11 (draft n3337):

Array-to-pointer conversion [conv.array]

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 result is a pointer to the first element of the array.

So when you try to pass an array to a function, it decays (recursively if multi-dimensional) to a pointer to its first element. Then that pointer is passed (by value) which is almost equivalent of a pass by reference call of the array.

But all other objects are passed by value, be them custom objects or object from the standard library.

For the stack vs. heap question, it is unrelated to the standard, because C++ has no notion of head and stack, but only automatic vs. dynamic variables. Simply common implementations use the stack for automatic variables and the heap for dynamic memory.

Let's go on one step further:

void f() {
    double arr_auto[1000];       // automatic array (stack on common implementations)
                                 //  will be automatically destroyed at end of block
    double* arr_heap = new int[1000]; // dynamically allocated array
                                      //  will require an explicit delete[]
    std::vector<int> vec(1000);  // vec is an automatic object (stack), 
                                 //  hosting a dynamic array of 1000 doubles
                    // everything (vector and content) will be destroyed at end of block

    g1(arr_auto);    // actually passes &(arr_auto[0]) a mere pointer to an automatic array
    g1(arr_heap);    // equally passes a pointer but to a dynamically allocated array
    g2(vec);         // assuming g2 is declared g2(vector<int>& v) passes a reference
    g3(vec);         // assuming g3 is declared g3(vector<int> v) constructs a copy of vec
    ...
}

For the last case (pass an object by value), an automatic copy of the object is constructed via the copy constructor. And containers from the standard library do allocate dynamic memory for their content - and their destructor ensure that the dynamic memory is freed when their life time ends. So you get a full copy of the original values allocated in dynamic memory (heap for common implementations), without needing to care for explicit deletion.

Hope it is more clear now...

Community
  • 1
  • 1
Serge Ballesta
  • 121,548
  • 10
  • 94
  • 199
0

1) Is there a better way?

When declaring array, you can't pass it to function by value, since you don't have copy constructor and operator=. to solve this issue you better use std::array. in your case it can be:

typedef std::array<std::array<bool,10>,10> bool10x10Array;

you gain default & copy constructors and operator= the memory will be allocate on stack for object declaration.

2) Does anyone know of any good reference that specifically targets whether an argument will be passed through Heap or Stack during the function calls?

Arguments are never passed via heap. The way argument passed is depending on the calling convention, when you passed a pointer or reference, you just pass the address of the memory block, you are not copy all the memory. if you want to work on a copy you must copy the memory block and pass the copy address. if you use struct or class you can use their copy constructor and pass them by value when you pass anything by value it usually copied to the stack.

3) Is there a better way to determine whether something is declared on Heap or Stack other than printing the address of the variable and determine by inspecting the address?

When declaring local variable the object will always be allocated on the stack. when you use dynamic allocation it will always be allocated on the heap. but you must notice that it is true for primitive type scalars and arrays. Class may be declared on stack and use also dynamic memory.

SHR
  • 7,149
  • 9
  • 32
  • 50
-1

Arguments are always passed on the stack. The only time arguments are "passed on the heap" (they never truly are) is when a new copy of an object is being made, and the object is allocating memory on the heap using new/malloc.

Two ways you could go about sending the array by value is by encapsulating the array in a struct (C way), or using an std::array (C++ way).

Most of this was already answered in the comments (thanks to @Richard Critten, @Bo Persson, and @Lundin), but I guess one complete answer would work better.

ErrorAtLine0
  • 169
  • 1
  • 8
  • **Wrong**. Arguments are generally not passed on the stack (which is not specified in the C++ standard), at least on x86-64. The [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) conventions dictate how arguments are passed, and on most current processors and OSes, they are usually passed in registers (see [this](https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI) for ABIs on PCs) – Basile Starynkevitch May 28 '18 at 11:47