Can a constexpr class have uninitialized but inaccessible objects? - c++

I'm a little unclear if I could have an object that has uninitialized values that are not accessible.
E.g.: Say like a stack based on an c-array. If I don't have any elements in the stack, then the elements stored could be uninitialized, but when I push an element onto the stack, I would use placement new to use the copy constructor and on pop, I would placement delete.
Actual access to the elements beyond the head of the stack would not be accessible, or accessing them would be UB (just like elements beyond the actual c-array).

Related

C++: how does C++ know to destruct smart pointers inside containers?

In The C++ Programming Language, there is the following example (section
3.2.4).
unique_ptr<Shape> read_shape(istream& is);
void user()
{
vector<unique_ptr<Shape>> v;
while (cin)
v.push_back(read_shape(cin));
draw_all(v);
// call draw() for each element
rotate_all(v,45);
// call rotate(45) for each element
} // all Shapes implicitly destroyed
Stroustrup is trying to make the point that by using unique_ptrs, one
doesn't have to manually loop through the vector and delete all
Shapes. I'm having trouble understanding why this is true.
The way I understand smart pointers is that if a smart pointer sptr is
allocated on the stack, with something like
std::unique_ptr<Shape> sptr(new Shape());
you don't need to call delete on it at the end of the function. However,
from what I can tell in the above example those smart pointers are not
on the stack, they're put inside the data array of v, which is on the
heap.
Whether the unique_ptr is on the stack or the heap doesn't really matter. What matters is that it will automatically call delete on the target pointer when its destructor runs.
When the vector goes out of scope, the vector's destructor runs. That destroys all contained elements (calling their destructors in the process) and then deallocates its heap buffer.
This is what destructors are for. You don't see the "manual loop" that destroys the unique pointers because that loop is within the destructor of the vector. All containers destroy their elements.
When the destructor for std::vector runs it calls the destructor for each object it contains. The destructor for std::unique_ptr calls delete/delete[] on the pointer it wraps, so all of the memory that was allocated will be cleaned up correctly.
When a std::unique_ptr itself is destructed or reset, it calls delete or delete[] (or a custom deleter that you specify) on the object/array that it is currently holding a pointer to.
If the std::unique_ptr is created in automatic memory, such as the stack, it is destructed when it goes out of scope.
If the std::unique_ptr is created in dynamic memory, such as the heap, it is destructed when delete is called on it.
A container owns the elements that it stores. It knows whether its elements are of a type that defines a destructor or not, and if so then it will call that destructor on each element when needed, such as when removing individual elements from the container, or when the container itself is destructed or cleared.
So, if you have a container of std::unique_ptr elements, they will be destructed for you when appropriate, which in turn will destruct the things that they are pointing at.
Yes, if you create something on the heap, you have to delete it yourself. Unlike automatic variables (those on the stack, even though the standard doesn't actually mandate the existence of a stack), the lifetime (scope) of those objects can continue across function return boundaries.
However, the vector here is not on the heap - it's actually an automatic variable that will undoubtedly store some of its information on the heap (the array holding the vector elements, most likely), but the variable itself is not.
That means, when it goes out of scope on exit from user(), the destructor is called for it. That destructor is smart enough to free the heap-specific stuff for the vector itself, and call the destructor for each element in the vector.
And, of course, destructing each of those elements may cause further destructors to be called. If one of those elements being destructed is a smart pointer, it will know that it needs to release its hold on the underlying pointer, by either freeing it or decrementing a count to say it has no further interest in it.

Why does a vector have to move its data members when reallocating

Assuming that a vector contains an array internally of std::aligned_storage instances that actually contain elements of the type the vector is templated on if the aligned_storage instance is in use.
When the vector has to allocate a new block of memory and move all its elements, why does it invoke the move constructor of each element in use and then destroy the old element? Why not just copy over all the bytes byte by byte and just delete the old array without calling destructors? This would make the new array an exact copy of the old array without the overhead of moving and destroying elements.
Maybe I'm a little tired and am missing something really basic. But I cannot think of a reason why this would not work.
It would not be safe to merely copy the bytes. Imagine, for example, that your object has two members, p and d, and p is a pointer that points to d. If you just copy the bytes, you'd copy the value of p that points to the old location of d, which has been destroyed.
This is a simple example, but in general, the reason for C++ constructors, destructors, copy and move constructors, is to allow your object to be "smarter" than just a sequence of bytes would be. Member variables have meaning, and that meaning is understood by your code, not by the compiler.

How should class fields be declared in C++?

I need to declare and initialize a vector as a field of a class named PixelOperator.
I am torn between these two declaration methods, the first is "on the heap", and the second "on the stack" (or at least, that is my interpretation).
vector<int>* field = new vector<int>();
vector<int> field = vector<int>();
If I choose to declare in style number 1, I need to call delete in the destructor of the class.
Which one should I choose, and why?
Also, if the class is initialized on the heap (ie. PixelOperator* op = new PixelOperator();), are fields initialized on the stack initialized on the heap?
Choose method 2. That would put the object on the stack, but the vector's implementation will most likely put the contents on the heap.
Also, you have the meanings reversed. 1 is on the heap, 2 is on the stack. 1 will require delete.
Your intuition is wrong in this instance. Approach (2) does not necessarily put the vector on stack. If PixelOperator object is declared locally and thus put on stack, the vector is put on stack as well, but if the PixelOperator object is put on heap using new operator, the vector also gets put on heap as part of that object. The difference in this instance would be that in approach (2) the vector is part of a contiguous block of memory together with other object fields, and in approach (1), the block of memory containing the object has in it address of another block of memory, which contains the vector. Of course, in approach (1) the vector ends up on heap regardless of whether the PixelOperator object is put on heap or on stack. Approach (2) is generally more desirable, as it allows for more transparency determining where the object gets allocated.
There is nothing to stumble on. There is never a reason to allocate std::vector<> (or any other standard container for that matter) on a heap. Simply never do this and you will be alright.

C++ vector passed by value: did I get it right?

Let's say I have a struct like this:
struct typeA
{
long first;
string second
double third;
};
If I declare
typeA myArray[100];
Then myArray is stored in the stack, consuming sizeof(typeA)*100 bytes of garbage data (until I store some actual data, at least).
Whenever I pass this array as a parameter, I'll always be passing a pointer to the first of the first element in the stack. So the pointer goes from stack to stack.
But if I declare
vector<int> myVector (4, 100);
Then the myVector object is actually stored in the stack, and it contains a pointer to the first element of an array of 4*sizeof(int) bytes stored in the heap, where the actual data is stored. So pointer goes from stack to heap.
Whenever I pass this vector as a parameter, if I add it to the parameter list like this:
vector<int> parameterVector
the function gets a copy of the myVector object and stores it in the stack.
But if I do it like this:
vector<int> &parameterVector
the function gets a reference to myVector stored in the stack, so I now have a variable stored in the stack, referencing a myVector object also stored in the stack, that contains a pointer to an array of actual elements stored in the heap.
Is this correct?
I have a few doubts here:
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
If I got the whole thing wrong and the actual elements are copied as well when passing a vector parameter by value, then why does C++ allow this, considering it discourages it with static arrays? (as far as I know, static arrays always get passed as a reference to the first element).
Thanks!
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
Typically the elements of the vector are stored in the free store using a dynamic array like
some_type* some_name = new some_type[some_size]
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
Typically a vector will have a pointer to the first element, a size variable and a capacity. It could have more but these are implementation details and are not defined by the standard.
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
No. copying the vector is an O(N) operation as it has to copy each element of the vector. If it did not then you would have two vectors using the same underlying array and if one gets destroyed then it would delete the array out from under the other one.
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
std::vector<> will allocate memory on the heap for all your elements, given, that you use the standard allocator. It will manage that memory and reallocate, when necessary. So no, there is no static array. It is more as you would handle a dynamic array in C, but without all the traps.
If you are looking for a modern replacement for C-Arrays, have a look at std::array<>. Be aware, that a std::array<> will copy all the elements as well. Pass by reference, if that is what you mean.
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
std::vector usually is a pointer to the first element, a size and a few more bits for internal usage. But the details are actually implementation specific.
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
No. Whenever the vector object gets copied to another vector object, all the elements will be copied.
If I got the whole thing wrong and the actual elements are copied as well when passing a vector parameter by value, then why does C++ allow this, considering it discourages it with static arrays? (as far as I know, static arrays always get passed as a reference to the first element).
The "static arrays" are a C-Legacy. You should simply not use them any more in new code. In case you want to pass a vector by reference, do so and nothing will be copied. In case you want the vector to be moved, move it, instead of copying it. Whenever you tell the compiler, you want to copy an object, it will.
OK, why is it that way?
The C-behavior is somehow inconsistent with the rest of the language. When you pass an int, it will be copied, when you pass a struct, it will be copied, when you pass a pointer, it will be copied, but when you pass an array, the array will not be copied, but a pointer to its first element.
So the C++ way is more consistent. Pass by value copies everything, pass by reference doesn't. With C++11 move constructors, objects can be passed by moving them. That means, that the original vector will be left empty, while the new one has taken over the responsibility for the original memory block.

Where does a std::vector allocate its memory?

Consider the following code snippet:
#include <vector>
using namespace std;
void sub(vector<int>& vec) {
vec.push_back(5);
}
int main() {
vector<int> vec(4,0);
sub(vec);
return 0;
}
Assuming "vec" has no space left to store the 5 in the "sub" function, where does it allocate new memory?
In the stack frame of the sub function? In that case the 5 would be deleted at the end of the sub function. But the stack frame of the main function can't grow, as the stack frame of the sub function lies on top of the stack at that moment.
Does a std::vector allocate memory for its elements on the heap?
But how does it free that heap memory?
If it's a local vector on the stack, the stack frame of a function including the vector is deleted in the end without signaling the vector that it will be deleted?
Does a std::vector allocate memory for its elements on the heap?
Yes. Or more accurately it allocates based on the allocator you pass in at construction. You didn't specify one, so you get the default allocator. By default, this will be the heap.
But how does it free that heap memory?
Through its destructor when it goes out of scope. (Note that a pointer to a vector going out of scope won't trigger the destructor). But if you had passed by value to sub you'd construct (and later destruct) a new copy. 5 would then get pushed back onto that copy, the copy would be cleaned up, and the vector in main would be untouched.
All containers in the STL are parameterized with template arguments, usually the last argument is called A or Allocator and defaults to std::allocator<...> where ... represents the type of the value stored within the container.
The Allocator is a class that is used to provide memory and build/destroy the elements in this memory area. It can allocate memory from a pool or directly from the heap, whichever you build the allocator from. By default the std::allocator<T> is a simple wrapper around ::operator new and will thus allocate memory on the heap as you inferred.
The memory is allocated on demand, and is deallocated at the very least when the vector's destructor is called. C++11 introduces shrink_to_fit to release memory sooner too. Finally, when the vector outgrow its current capacity, a new (larger) allocation is made, the objects are moved to it, and the old allocation is released.
As will all local variables, the destructor is called when executed reaches the end of the scope it has been declared into. So, before the function is exited, the vector destructor is called, and only afterward does the stack shrinks and control returns to the caller.
Also note that your vector (vec) is object itself. It resides on the stack and when this object goes out of scope (which is end of main in your case), it is destructed. Memory for elements is allocated during initialization of this object and released with its destruction, which is a lovely example of RAII idiom, since the resource management of elements is tied to the lifespan of vector object.
Because you gave sub the adress of the vector in the heap, it will allocate in the heap. If there's no space left, exception should be thrown.