how Objects in C++ stored? in heap or stack? - c++

#include <string>
#include <iostream>
class Type {
public:
int x;
Type(int a)
{
x = a;
}
Type(const Type& type1)
{
std::cout << "copy" << std::endl;
}
};
Type Func()
{
Type s(1);
std::cout << &s << std::endl;
return s;
}
int main()
{
Type c = Func();
std::cout << &c << std::endl;
std::cout << c.x << std::endl;
system("pause");
}
C++ allocate memory for object in heap or stack? In Func, suppose "s" is allocated in stack, then why it don't be deconstructed? Why can i stiil call it in main(). I am very confused.

By default, objects are are stored in the stack (unless their implementation has a dynamic allocator, e.g. a map). If you have your own class and instanciate it, it will live in the stack. However, this is not recommended since the stack ougth to be considered a precious and scarce resource. If you were to have a heavy object, or many light objects, it is better to allocate them dynamically.
In modern C++ versions, we have what is called move semantics and move constructors (which can be automatically generated by the compiler). Basically, the compiler optimizes your code. In this case, it would be inefficient to copy the object s to c when s is going to be destroyed anyway. What the move constructor does is basically steal the data from s and give it directly to c (in this case, just using c as an alias for the memory location in which s is stored).

Related

c++ - Destructor called on assignment

I'm still learning the basics of c++ so I may not have had the correct vocabulary to find the answer to my question but I couldn't find this mentioned anywhere.
If I have a class with a constructor and destructor why does the destructor get called on the new data when I am assigning to the class?
For example:
#include <iostream>
class TestClass {
public:
int* some_data;
TestClass() {
std::cout << "Creating" << std::endl;
some_data = (int*)malloc(10*sizeof(int));
}
~TestClass() {
std::cout << "Deconstructing" << std::endl;
free(some_data);
}
TestClass(const TestClass& t) : some_data{t.some_data} {
std::cout << "Copy" << std::endl;
}
};
int main() {
TestClass foo;
std::cout << "Created once" << std::endl;
foo = TestClass();
std::cout << "Created twice" << std::endl;
}
which prints:
Creating
Created once
Creating
Deconstructing
Created twice
Deconstructing
free(): double free detected in tcache 2
Aborted (core dumped)
So after following this in the debugger it appears the deconstructor is called on the newly created data which is confusing to me. Shouldn't the original data be freed once and then at the end of execution the new data should be freed? It seems like the original data is never freed like this.
Your object owns a raw pointer to allocated memory, but does not implement a proper copy constructor that makes an allocation and copies the data behind the pointer. As written, when you copy an object, the pointer is copied, such that now two objects point to the same address (and the old one that the just-assigned-to object is leaked.)
When the temporary goes out of scope, it deletes its pointer but the copy (foo) still points to it. When foo goes out of scope, it deletes the same pointer again, causing this double free error you're seeing.
If you need to write a destructor to clean up, you almost always need to also provide copy and assignment operations, or disable them.
SUGGESTIONS:
hold the pointer in a std::unique_ptr which will fail to compile if you try to copy it. This forces you to deal with the issue. Also, malloc and free are mainly for C or low-level C++ memory management. Consider using new and delete for allocations instead. (unique_ptr uses delete by default, not free, and you must not mix them.)
alternately, delete the copy constructor and assignment operator
also, consider when you want to move from an xvalue (temporary or moved lvalue), you can pilfer the allocation from the right-hand-side. So this class is a good candidate for move constructor and move assignment.
Most of the comments and a few details more in code:
#include <iostream>
#include <array>
#include <memory>
class TestClass
{
// members of a class should not be public
private:
// TestClass owns the data, this is best modeled
// with a unique_ptr. std::array is a nicer way of
// working with arrays as objects (with size!)
std::unique_ptr<std::array<int, 10>> some_data;
public:
TestClass() :
some_data{ std::make_unique<std::array<int,10>>() }
{
std::cout << "Creating" << std::endl;
// set everything in the array to 0
std::fill(some_data->begin(), some_data->end(), 0);
}
~TestClass()
{
std::cout << "Destructing" << std::endl;
// no need to manually delete a std::unique_ptr
// its destructor will free the memory
// and that will be called as part of this destructor
}
TestClass(const TestClass& t) :
// when you copy a class the copy should have its
// own copy of the data (to avoid deleting some data twice)
// or you must chose shared ownership (lookup std::shared_ptr)
some_data{ std::make_unique<std::array<int,10>>() }
{
std::cout << "Copy" << std::endl;
// copy data from t to this instances array
// (note this would not have been necessary
// it your array was just a non-pointer member,
// try that for yourself too.)
std::copy(some_data->begin(), some_data->end(), t.some_data->begin());
}
TestClass(TestClass&& rhs) :
some_data{ std::move(rhs.some_data) } // transfer ownership of the unique_pointer to this copy
{
std::cout << "Move" << std::endl;
}
// Important this assignement operator is used in your original code too
// but you couldn't see it!
TestClass& operator=(const TestClass& t)
{
some_data = std::make_unique<std::array<int, 10>>();
std::copy(some_data->begin(), some_data->end(), t.some_data->begin());
std::cout << "Assignment" << std::endl;
return *this;
}
};
int main()
{
TestClass foo;
std::cout << "Created once" << std::endl;
foo = TestClass();
std::cout << "Created twice" << std::endl;
TestClass bar{ std::move(foo) };
std::cout << "Moved" << std::endl;
}

How to pass the ownership of an object to the outside of the function

Is there any method that can pass the ownership of an object created in the function on the stack memory to the outside of the function without using copy construction?
Usually, compiler will automatically call destruction to the object on the stack of a function. Therefore, if we want to create an object of a class(maybe with some specific parameters), how can we avoid wasting lots of resources copying from temp objects?
Here is one common case:
while(...){
vectors.push_back(createObject( parameter ));
}
So when we want to create objects in a iteration with some parameters, and push them into a vector, normal value passed way will take a lot of time copying objects. I don't want to use pointer and new objects on the heap memory as user are likely to forget delete them and consequently cause memory leak.
Well, smart pointer maybe a solution. But..less elegent, I think. hhhh
Is there any way of applying rvalue reference and move semantics to solve this problem?
Typically, returning an object by value will not copy the object, as the compiler should do a (named) return value optimization and thereby elide the copy.
With this optimization, the space for the returned object is allocated from the calling context (outer stack frame) and the object is constructed directly there.
In your example, the compiler will allocate space for the object in the context where createObject() is called. As this context is an (unnamed) parameter to the std::vector<T>.push_back() member function, this works as an rvalue reference, so the push_back() by-value will consume this object by moving (instead of copying) it into the vector. This is possible since if the generated objects are movable. Otherwise, a copy will occur.
In sum, each object will be created and then moved (if moveable) into the vector.
Here is a sample code that shows this in more detail:
#include <iostream>
#include <string>
#include <vector>
using Params = std::vector<std::string>;
class Object
{
public:
Object() = default;
Object(const std::string& s) : s_{s}
{
std::cout << "ctor: " << s_ << std::endl;
}
~Object()
{
std::cout << "dtor: " << s_ << std::endl;
}
// Explicitly no copy constructor!
Object(const Object& other) = delete;
Object(Object&& other)
{
std::swap(s_, other.s_);
std::cout << "move: traded '" << s_ << "' for '" << other.s_ << "'" << std::endl;
}
Object& operator=(Object other)
{
std::swap(s_, other.s_);
std::cout << "assign: " << s_ << std::endl;
return *this;
}
private:
std::string s_;
};
using Objects = std::vector<Object>;
Object createObject(const std::string& s)
{
Object o{s};
return o;
}
int main ()
{
Objects v;
v.reserve(4); // avoid moves, if initial capacity is too small
std::cout << "capacity(v): " << v.capacity() << std::endl;
Params ps = { "a", "bb", "ccc", "dddd" };
for (auto p : ps) {
v.push_back(createObject(p));
}
return 0;
}
Note that the class Object explicitly forbids copying. But for this to work, the move constructur must be available.
A detailed summary on when copy elision can (or will) happen is available here.
Move semantics and copy elison of vectors should mean the elements of the local std::vector are in fact passed out of the object and into your local variable.
Crudely you can expect the move constructor of std::vector to be something like:
//This is not real code...
vector::vector(vector&& tomove){
elems=tomove.elems; //cheap transfer of elements - no copying of objects.
len=tomove.elems;
cap=tomove.cap;
tomove.elems=nullptr;
tomove.len=0;
tomove.cap=0;
}
Execute this code and notice the minimum number of objects are constructed and destructed.
#include <iostream>
#include <vector>
class Heavy{
public:
Heavy(){std::cout<< "Heavy construction\n";}
Heavy(const Heavy&){std::cout<< "Heavy copy construction\n";}
Heavy(Heavy&&){std::cout<< "Heavy move construction\n";}
~Heavy(){std::cout<< "Heavy destruction\n";}
};
std::vector<Heavy> build(size_t size){
std::vector<Heavy> result;
result.reserve(size);
for(size_t i=0;i<size;++i){
result.emplace_back();
}
return result;
}
int main() {
std::vector<Heavy> local=build(5);
std::cout<<local.size()<<std::endl;
return 0;
}
Move semantics and copy elison tend to take care of this problem C++11 onwards.
Expected output:
Heavy construction
Heavy construction
Heavy construction
Heavy construction
Heavy construction
5
Heavy destruction
Heavy destruction
Heavy destruction
Heavy destruction
Heavy destruction
Notice that I reserved capacity in the vector before filling it and used emplace_back to construct the objects straight into the vector.
You don't have to get the value passed to reserve exactly right as the vector will grow to accommodate values but it that will eventually lead to a re-allocation and move of all the elements which may be costly depending on whether you or the compiler implemented an efficient move constructor.

"memcopy" style construction of an object in C++

In certain embedded situations, memory needs to be moved with memcopy style functions (such as from external memory, or using closed API calls).
When such a C++ object needs to be moved this way, however it doesn't have a default constructor, you can't do something like this, :
class Object {
//local data
public:
Object(/* not a default constructor */){}
}
//elsewhere:
Object o; //compiler will complain here...
memcpy_like_function(src_address, &o, sizeof(o));
because Object doesn't have a default constructor, and thus the compiler will complain about creating Object o.
Some notes from things that have shown up in the comments:
memcpy_like_function is like memcpy, it isn't actually memcpy. The src_address isn't a pointer to an address I can reach, or an int representing a pointer to an address I can reach. It is an int representing an address in a memory space I can't reach. The only way for me to access this memory space is with this function.
Object doesn't have a default constructor, has no virtual functions, is neither inherited from, nor inherits anything. Object is trivially copyable.
What is the correct way to deal with creating such an object in this situation, without putting it on the heap? Preferably, I would like to get a stack allocated object that will behave correctly with scope and destructors. For the purposes of this question, Object is not inheriting from anything.
This seems like a horribly bad idea, but assuming that your memcpy_like_function actually works, then you can just add a constructor to Object
class Object {
//local data
public:
Object(void* src_address)
{
memcpy_like_function(src_address, this, sizeof(*this));
}
};
//elsewhere:
Object o(src_address);
because Object doesn't have a default constructor
When Object doesn't have a default constructor,
//Object o;//NG
there is no way to construct Object unless call another ctor or factory function. Because of that, you cannot call memcpy-like function.
When you have way to construct Object, to use memcpy-like function, Object class must grantee that it is trivially copyable class and standard-layout class(not equal to POD class).
trivial class : trivially copyable class && has no default user-defined constructor
POD class : trivial class && standard-layout class
You cannot safely copy an object using a memcpy-like function unless the object is a POD type. If the object is a POD type, you should be able to use:
char destination[sizeof(Object)];
memcpy_like_function(src_address, destination, sizeof(destination));
Object* ptr = reinterpret_cast<Object*>(destination);
My gut-feel says that that should work under all compilers for POD types. Whether it is cause for undefined behavior under some rules of the standard, I am not sure.
If that is cause for undefined behavior under some rules of the standard, you won't be able to save a POD-type to a binary file and read it from the binary file in a standards compliant manner. They rely on the bit-pattern written to a file and read from a file to represent the object.
The following program produces the expected result under g++.
#include <iostream>
#include <cstring>
struct Object
{
int i;
double d;
Object(int ii, double dd) : i(ii), d(dd) {}
};
int main()
{
Object o1(10, 20.34);
char dest[sizeof(Object)];
memcpy(dest, &o1, sizeof(dest));
Object* ptr = reinterpret_cast<Object*>(dest);
std::cout << o1.i << ", " << o1.d << std::endl;
std::cout << ptr->i << ", " << ptr->d << std::endl;
}
Update, in response to OP's comments
The following program works as expected under g++.
#include <iostream>
#include <cstring>
struct Object
{
int i;
double d;
Object(int ii, double dd) : i(ii), d(dd) {}
};
Object testFunction(Object o1)
{
char dest[sizeof(Object)];
memcpy(dest, &o1, sizeof(dest));
Object* ptr = reinterpret_cast<Object*>(dest);
return *ptr;
}
int main()
{
Object o1(10, 20.34);
Object o2 = testFunction(o1);
std::cout << o1.i << ", " << o1.d << std::endl;
std::cout << o2.i << ", " << o2.d << std::endl;
o2.i = 25;
o2.d = 39.65;
std::cout << o2.i << ", " << o2.d << std::endl;
}
What you could do is simply use an array of bytes, then cast.
Note: what you are doing is not really good C++ practice, typically you should use assignment operators or copy constructors, and you should stick to the safer C++ casts rather than a brute-force C-style cast.
Anyway, that being said, this code will work:
class Object {
int i;
public:
Object(int i) : i(i) {}
void foo() const {
std::cout << i << std::endl;
}
};
void bla() {
Object one(1);
char *bytes = new char[sizeof(Object)];
memcpy(bytes, &one, sizeof(Object));
Object &anotherOne = (Object &) *bytes;
anotherOne.foo();
const Object &oneMore = (Object) *bytes;
oneMore.foo();
Object *oneMoreTime = (Object *) bytes;
oneMoreTime->foo();
delete[] bytes;
}
The output is:
1
1
1
In summary, you need to allocate a region of memory on the stack or the heap that will become the Object instance.

Why doesn't std::unique_ptr have an aliasing constructor like std::shared_ptr has?

I've just discovered std::shared_ptr's "aliasing constructor" and find myself asking "why doesn't std::unique_ptr have an corresponding one?
That is, if you want to allocate a Foo so that you can pass its Bar member to a function that should entirely manage the lifetime of the Foo, wouldn't it be nice to be able to do so?
#include <memory>
struct B {}
struct A {
B b;
}
void f(std::unique_ptr<B> b);
std::unique_ptr<A> a = std::make_unique<A>();
std::unique_ptr<B> b { std::move(a), &(a->b) }; // a now invalid.
f(std::move(b)); // f now responsible for deleting the A.
This works with std::shared_ptr ( http://ideone.com/pDK1bc )
#include <iostream>
#include <memory>
#include <string>
struct B {
std::string s;
};
struct A {
B b;
A(std::string s) : b{s} {};
~A() { std::cout << "A deleted." << std::endl; }
};
void f(std::shared_ptr<B> b) {
std::cout << "in f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
}
int main() {
std::shared_ptr<A> a = std::make_shared<A>("hello");
std::shared_ptr<B> b { a, &(a->b) };
a.reset(); // a now invalid.
std::cout << "before f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
f(std::move(b)); // f now responsible for deleting the A.
std::cout << "after f" << std::endl;
return 0;
}
outputs the expected
before f, b->s = hello (use_count=1)
in f, b->s = hello (use_count=1)
A deleted.
after f
Is there a logical reason why such a thing wasn't included? And/or, is it a bad idea to emulate it with a unique_ptr<B> with a custom deleter that deletes the A?
I believe the “problem” is that, unlike std::shared_ptr, std::unique_ptr's deleter is not type-erased. The default deleter of std::unique_ptr<T> (which has zero size, encoded into the type itself as a barely visible default type parameter) is simply [](T * p){ delete p; }. But it is clear that a std::unique_ptr<B> that was created via std::make_unique<B> and one that was made by pointing to a B member of an A object cannot have the same deleter. The deleter for the latter case would have to do some pointer arithmetic to obtain the original A * pointer back. Those two deleters could only have the same type if both would store an offset or an internal pointer to the original object. And that would no longer have zero size. std::unique_ptr was designed to have zero overhead compared to doing new and delete manually, which is a Good Thing. I don't see any immediate drawbacks from using your own deleters that store that additional pointer, though I'd still have to come across a use-case where I'd find this useful.
shared_ptr has reference counting overhead. In its reference counting block it also stores an explicit deleter (because if you are storing on the heap, what is a few more bytes?)
This is also why a shared_ptr to a base type can remember to delete derived types without a virtual dtor.
unique_ptr, on the other hand, stores its deleter in the instance, and the default deleter is stateless -- 0 bytes used. This makes unique_ptr zero overhead over a raw pointer in terms of memory usage.
A stateless deleter cannot remember to delete something else.
You can add a stateful deleter to unique_ptr that supports aliasing, but then you'll have to alias manually. One of the constructors takes both a pointer and a deleter.

How to avoid big memory allocation with std::make_shared

Let's say that I have some arbitrary class, A:
class A {
//... stuff
};
I want to call into an external API that takes in a shared pointer to some type, like so (I cannot change this interface):
//...much later
void foo(std::shared_ptr<A> _a){
//operate on _a as a shared_ptr
}
However, in the (legacy) code I'm working with, the class A instance I'm working with is allocated on the stack (which I cannot get around):
A a;
//...some stuff on a
//Now time to call foo
On top of this, an instance of class A is quite large, on the order of 1 GB per instance.
I know I could call
foo(std::make_shared<A> a);
but that would allocate memory for a copy of A, which I would really like to avoid.
Question
Is there a way to hack together some call to std::make_shared (possibly with move semantics) so that I am not forced to allocate memory for another instance of class A?
I've tried something like this:
foo(std::make_shared<A>(std::move(a)));
But from what I can tell, a new instance of A is still created.
Example code
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
A(int _var=42) : var(_var){cout << "Default" << endl;}
A(const A& _rhs) : var(_rhs.var){cout << "Copy" << endl;}
A(A&& _rhs) : var(std::move(_rhs.var)){cout << "Move" << endl;}
int var;
};
void foo(std::shared_ptr<A> _a){
_a->var = 43;
cout << _a->var << endl;
}
int main() {
A a;
cout << a.var << endl;
foo(std::make_shared<A>(std::move(a)));
cout << a.var << endl;
a.var = 44;
foo(std::make_shared<A>(std::move(a)));
cout << a.var << endl;
return 0;
}
Output:
Default 42 Move 43 42 Move 43 44
This is possible with the shared_ptr constructor that allows for an "empty instance with non-null stored pointer":
A x;
std::shared_ptr<A> i_dont_own(std::shared_ptr<A>(), &x);
(It's "overload (8)" on the cppreference documentation.)
If you know that shared pointer you pass to foo() will not get stored, copied etc, ie will not outlive your object you can make std::shared_ptr pointed to object on the stack with empty deleter:
void emptyDeleter( A * ) {}
A a;
foo( std::shared_ptr<A>( &a, emptyDeleter ) );
Again you need to make sure that shared pointer or it's copy will not outlive the object and well document this hack.
Assuming class A supports move semantics, do this:
std::shared_ptr<A> newA = make_shared<A> (std::move (_a));
Do not use _a anymore, use only newA. You can now pass newA to the function.
If class A does not support move semantics, there is no safe/sane way to do this. Any hack will only happen to work, and may break in the future. If you control enough of the class code, you may be able to add support for move semantics.
But from what I can tell, a new instance of A is still created.
Why do you care? What you're trying to avoid is copying all the data in the instance, and this does that.
The point of move semantics is to move the data from one instance to another without having to do an allocate/copy/free. Of course, this makes the original instance "empty", so don't use that anymore.