Memory and scope management - c++

I have a doubt about the scope and the memory management in c++. Here is the case I'm having troubles:
Abc function f()
{
Abc c;
return c;
}
Abc d = f();
if(d) cout << "hi";
Would it say the "hi"? I mean... the Abc created in f() is not dynamic (we didn't write a new)... but we are returning the value, so we mantain a reference to the object. Would it has value, or as soon as it gets out of its scope it dies?
Thanks!

#include <iostream>
using std::cout;
using std::endl;
class Abc
{
int m_value = 0;
public:
Abc()
{
cout << "Default Constructor" << std::endl;
}
Abc(const Abc& _source)
{
cout << "Copy Constructor" << std::endl;
//copy stuff
}
Abc& operator=(const Abc& _source)
{
cout << "assignment operator" << std::endl;
if (this == &_source)
return *this;
//copy stuff
return *this;
}
Abc(const Abc&& _source)
{
cout << "Move Constructor" << std::endl;
//move stuff
}
Abc& operator=(const Abc&& _source)
{
cout << "move assignment operator" << std::endl;
//move stuff
return *this;
}
~Abc()
{
cout << "Destructor"<< std::endl;
}
void setValue(int _value)
{
m_value = _value;
}
int getValue()
{
return m_value;
}
};
Abc f()
{
Abc c;
c.setValue(100);
cout << "c value: " << c.getValue() << endl;
return c;
}
int main()
{
Abc d = f();
cout << "d value: " << d.getValue() << endl;
d.setValue(200);
cout << "d value: " << d.getValue() << endl;
}
Here is the output:
Default Constructor
c value: 100
d value: 100
d value: 200
Destructor
From here you can see that the compiler is smart enough to reuse allocated object without making any dumb copies(C++98/03, C++11 same output).
Compiled with MinGW(GCC 4.7.1).

In your case it is impossible to make an exact statement, in the second case below:
Abc* function f()
{
Abc *c = new Abc();;
return c;
}
Abc* d = f();
if(d) cout << "hi";
And yes, it would say "hi", the difference is that in the first case, c is kept in Stack while in the second case it is kept in Heap. In your case, typing if(d) is not a good method for checking whether object is alive because it is defined on the Stack.
In order to check your case you can add a log to the destructor of Abc and see whether it will be hit or not. You will observe that the destructor of Abc is called when you return the object with f(). But this does not mean that the object is dead. Only its destructor is called. But in this case you can not use destructors properly. This is one of the reasons why pointers to objects are chosen instead of defining them directly.

Abc f()
{
Abc c;
return c;
}
create c of type Abc, copy it and return from function (with NRVO copy may be elided).
Abc d = f();
if(d) cout << "hi";
create d and copy-initialize it with returned value of function f. What is Abc type? If it has operator bool (or operator T() where T is implicitly convertible to bool) - may be it will print "hi".

Related

Any way to detect whether an object of my class is create on stack?

Now I need to detect whether my class is created as a stack/global/thread_local variable, for example:
class Foo {
public:
Foo() {
if(im_on_stack) {
std::cout << "I'm on stack" << std::endl;
} else if(im_in_global) {
std::cout << "I'm in global" << std::endl;
} else if(im_a_thread_local) {
std::cout << "I'm a thread_local" << std::endl;
} else {
std::cout << "I'm on ohters location" << std::endl;
}
}
};
class Bar {
Foo mFoo;
};
Foo gFoo;
thread_local Foo tFoo;
int main() {
Foo lFoo;
}
and the out put should be:
I'm on ohters location
I'm in global
I'm a thread_local
I'm on stack
This there any way in C++ I can do this?
Edit:
why I'm doing this:
I'm writing a garbage collection library, and I got a class, let's call it gc_ptr, I need to know if this gc_ptr is a gc root (which is create on the location I mentioned) or not (which is a member of another class)
Edit2:
According to the concept of gc root, which is a reference which is not on a heap, I should probably asked in this way: can I detect if my class is create on the heap? But I think on heap or on stack make this question no difference.
Short answer: No. Not with standard C++. There may be compiler or OS specific solutions, but nothing portable.
I guess you could make a heuristic to detect stack allocated objects by detecting in their constructor whether their address is close to a stack allocated variable. Assuming that the stack and the heap have completely different memory addresses it should work. Completely undefined behaviour though according to the standard. e.g.:
#include <iostream>
#include <memory>
struct A
{
A()
{
int test = 0; // test is on the stack
auto distance = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(&test);
isStack = std::abs(distance) < 1024; // completely arbitrary magic number, will need to experiment
}
bool isStack;
};
int main()
{
std::cout << "stack: " << A().isStack << "\n";
std::cout << "stack: " << std::make_unique<A>()->isStack << "\n";
}
I don't think you could expand this technique to thread local variables. You'd also need to take care in copy constructors and assignment operators to handle copying from a stack to a heap object and vice versa.
This is not part of the spec, so no.
If you told us on what system/os you are working, maybe we can assist - some systems may provide the stack address and size - usually this is available in embedded devices as part of the compiler output (the address), and as input (the size) as part of the environment/project configuration.
What I wrote in my comment:
Can be done to some extent: Assuming, you need it only for a certain kind of classes: You have to overload new (or wrap dynamic construction in a static create). You have to derive all considered classes from a base class with a specific constructor. To pass info from new to the constructor is a bit tricky. In our case, we used a global set where new remembered pointers to created instances and the corresponding constructor looked into it to determine whether creation was done by new. That was sufficient for us. (About the other topics - no idea...)
A demo:
#include <iostream>
#include <set>
class Object {
private:
static thread_local std::set<void*> pNewSet;
bool _isNewed;
public:
Object();
Object(const Object&) = delete;
const Object& operator=(const Object&) = delete;
~Object() = default;
static void* operator new(size_t size);
bool isNewed() const { return _isNewed; }
private:
static std::set<void*>& getNewPtrs()
{
static thread_local std::set<void*> pNewSet;
return pNewSet;
}
};
void* Object::operator new(size_t size)
{
std::set<void*> &pNewSet = getNewPtrs();
void *p = ::operator new(size);
if (p) pNewSet.insert(p);
return p;
}
Object::Object(): _isNewed(false)
{
std::set<void*> &pNewSet = getNewPtrs();
std::set<void*>::iterator iter = pNewSet.find((void*)this);
if (iter != pNewSet.end()) {
_isNewed = true;
pNewSet.erase(iter);
}
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
// a global static instance
static Object o;
int main()
{
DEBUG(std::cout << o.isNewed() << '\n');
// a static instance (local scope)
DEBUG(static Object o1);
DEBUG(std::cout << o1.isNewed() << '\n');
// a local instance
DEBUG(Object o2);
DEBUG(std::cout << o2.isNewed() << '\n');
// as members
DEBUG(struct Composed { Object o1, o2; } comp);
DEBUG(std::cout << comp.o1.isNewed() << ' ' << comp.o2.isNewed() << '\n');
// created with new
DEBUG(Object *pO = new Object());
DEBUG(std::cout << pO->isNewed() << '\n');
DEBUG(delete pO);
// created as members in an object created with new
DEBUG(Composed *pComp = new Composed());
DEBUG(std::cout << pComp->o1.isNewed() << ' ' << pComp->o2.isNewed() << '\n');
DEBUG(delete pComp);
}
Output:
std::cout << o.isNewed() << '\n';
0
static Object o1;
std::cout << o1.isNewed() << '\n';
0
Object o2;
std::cout << o2.isNewed() << '\n';
0
struct Composed { Object o1, o2; } comp;
std::cout << comp.o1.isNewed() << ' ' << comp.o2.isNewed() << '\n';
0 0
Object *pO = new Object();
std::cout << pO->isNewed() << '\n';
1
delete pO;
Composed *pComp = new Composed();
std::cout << pComp->o1.isNewed() << ' ' << pComp->o2.isNewed() << '\n';
0 0
delete pComp;
Live Demo on Compiler Explorer
Notes:
The copy constructor and assignment operator of Object are deleted intenionally.
Derived classes may provide a copy constructor but it has to call Object::Object().
The sample doesn't consider other flavors of new (e.g. operator new[] or the align variants since C++17). That should be done in productive code.
No, but you can prevent creation of objects on heap/stack.
To prevent creation on stack make the destructor private/protected:
class heap_only
{
public:
void release() const { delete this; }
protected:
~heap_only() {}
};
struct heap_only_deleter
{
void operator()( heap_only* p ) { p->release(); }
};
using up_heap_only = std::unique_ptr<heap_only, heap_only_deleter>;
//...
heap_only ho; // fails
heap_only* pho = new heap_only();
pho->release();
up_heap_only up{ new heap_only() };
To prevent creation on heap make the new operators private/protected:
class stack_only
{
protected:
static void* operator new( std::size_t );
static void* operator new[]( std::size_t );
};
//...
stack_only* pso = new stack_only(); // fails
stack_only so;
Regarding your edits, and just for fun:
void* pstart;
bool is_on_stack( void* p )
{
int end;
return pstart >= p && p > &end;
}
int globalint;
int main()
{
//
int start;
pstart = &start;
//
int stackint;
std::cout << std::boolalpha
<< is_on_stack( &globalint ) << std::endl
<< is_on_stack( &stackint ) << std::endl
<< is_on_stack( new int );
//...
}

Is it safe to call function accepting parameters by r-value reference twice with moved object?

I have the following piece of code. I expected it to fail, i.e. I thought that move constructor would execute when entering 'send' function and, when trying to call 'send' again this should be an invalid operation ('a' is no longer a valid object because it was moved from). But somehow this code executes without any problem.
Output shows that move constructor is not even executed.
#include <iostream>
using namespace std;
struct A {
int *ptr;
A() { cout << "ctor A" << endl; ptr = new int(1); }
A(A&& o) { cout << "move ctor" << endl; ptr = o.ptr; o.ptr = nullptr; }
~A() { cout << "dtor" << endl; delete ptr; }
void send() { cout << *ptr << endl; }
};
bool send(A&& a, int i)
{
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}
int main()
{
A a;
if(!send(move(a),0))
send(move(a),1);
}
Output:
ctor A
returning
sending
1
dtor
However when when I change the 'send' method to accept A objects by value, the problem appears exactly how I had imagined. Move ctor is called, and when second time 'send' is called, 'a' is not valid, we have segmentation fault.
bool send(A a, int i)
{
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}
Result:
ctor A
move ctor
returning
dtor
move ctor
sending
Segmentation fault
So, move constructor is only called when moved object is passed by value. Ok, I got it.
My question however is this: is it safe to declare function 'send' this way, i.e. to accept parameters by r-value reference and then call it with moved object multiple times? I know that std::move doesn't really move anything, only creates r-value reference, but anyhow: is it safe? Or, in other words, is there a guideline which says "Don't do this"?
[https://wandbox.org/permlink/R5spfEGI7WZR9lwR][1]
If you actually move the object within the send function, then you will see the behavior you expect (segmentation fault when a.send is called). For example:
bool send(A &&a, int i)
{
A b = move(a);
if (i == 0) {
cout << "returning" << endl;
return false;
}
cout << "sending" << endl;
a.send();
return true;
}

Explaining constructor and copy constructor example

I have this code and I can understand what happening with the contractor of class Fat.
#include <iostream>
using namespace std;
class Block{
int data;
public:
Block(int i = 10) : data(i){
cout << "I just created a Block " << endl;
}
~Block() {
cout << "I will destroy a Block with " << data << endl;
}
void inc() {
data++;
}
};
class A{
Block& block1;
Block block2;
public:
A(Block& blk) : block1(blk), block2(blk) {
cout << "I just created an A " << endl;
}
A(const A& a): block1(a.block1), block2(a.block2) {
cout << "I just created an A by copying but I will also do bad things" << endl;
block1.inc(); block2.inc();
}
~A() {
cout << "I will destroy an A " << endl;
}
void inc() {
block1.inc(); block2.inc();
}
};
class Fat{
A a;
A& ra;
A* pa;
public:
Fat(A& da) : a(da),ra(da) {
pa = new A(da);
cout << "Fat just created !" << endl;
}
~Fat() {
delete pa;
cout << "Fat to be destroyed !" << endl;
}
void inc() {
a.inc();
ra.inc();
pa->inc();
}
};
int main(){
Block block;
A a(block);
Fat fat(a);
fat.inc();
return 0;
}
and the result of this :
I just created a Block
I just created an A
I just created an A by copying but I will also do bad things
I just created an A by copying but I will also do bad things
Fat just created !
I will destroy an A
I will destroy a Block with 12
Fat to be destroyed !
I will destroy an A
I will destroy a Block with 12
I will destroy an A
I will destroy a Block with 11
I will destroy a Block with 15
Why does the copy constructor run twice?
The first "I just created an A by copying but I will also do bad things"comes from this line:
Fat(A& da) : a(da), ra(da) {
a(da) this one calls A's copy constructor
the seconds one from the constructer of class fat:
Fat(A& da) : a(da), ra(da) {
pa = new A(da); //HERE!!
cout << "Fat just created !" << endl;
}
again, with pa = new A(da); you call A's copy constructor.
edit: thank you for formatting your code
The first copy is made to initialise the a member variable in Fat:
Fat(A& da) : a(da), ra(da) {
Then the line
pa = new A(da);
creates a new instance of A on the free store by copying da hence it calls the copy constructor. If instead you wanted to make a pointer to an existing instance of A you should write
pa = &da;

Move constructor called with lambda

I am trying to understand how lambdas work in C++ in depth. I have written the following piece of code.
#include <iostream>
#include <functional>
struct A
{
A() { std::cout << "A" << (data = ++count) << ' '; }
A(const A& a) { std::cout << "cA" << (data = a.data + 20) << ' '; }
A(A&& a) { std::cout << "mA" << (data = std::move(a.data) + 10) << ' '; }
~A() { std::cout << "dA" << data << ' '; }
int data;
static int count;
};
int A::count = 0;
void f(A& a, std::function<void(A)> f)
{
std::cout << "( ";
f(a);
std::cout << ") ";
}
int main()
{
A temp, x;
auto fun = [=](A a) {std::cout << a.data << '|' << x.data << ' ';};
std::cout << "| ";
f(temp, fun);
std::cout << "| ";
}
The output is below.
A1 A2 cA22 | cA42 mA52 dA42 ( cA21 mA31 31|52 dA31 dA21 ) dA52 | dA22 dA2 dA1
This is quite clear to me, except for the 'mA52' move constructor call. Note that I am using variable capture by value, so without the move constructor, the copy-constructor would be called here. Why is there an additional copy/move at this step? One would expect the object to be copied only once when fun is passed by value as an argument to f. Furthermore, the first copy of the object is immediately destroyed. Why? What is this intermediary copy?
Let's call your lambda type L. It's unnamed, but it gets confusing to refer to it without a name.
The constructor std::function<void(A)>(L l) takes L by value. This involves creating a copy of the original fun.
The constructor then moves the lambda from l into some storage managed by the std::function<void(A)> wrapper. That move also involves moving any captured entities.
std::function<void(A)> takes the function object you pass to it by value (this is the cA42 in your output). It then moves the function object in to its internal storage (this is the mA52).

Copy Constructor Undefined Call

This is the full example (source book: C++ From Ground Up, 3rd Edition, page 219-320):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { cout << "s: " << s <<" ,Freeing s\n"; if(s) delete [] s;}
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(const sample &ob); // overload assignment
};
// Normal constructor.
sample::sample() {
s = new char('\0'); // s points to a null string.
cout << "Normal constructor: s: " << strlen(s) << endl;
}
// Copy constructor.
sample::sample(const sample &ob) {
cout << "Copy constructor: ob.s: "<< ob.s << " ,strlen(ob.s): " << strlen(ob.s) << "\n";
s = new char[strlen(ob.s)+1];
strcpy(s, ob.s);
}
// Load a string.
void sample::set(char *str) {
s = new char[strlen(str)+1];
strcpy(s, str);
}
// Overload assignment operator.
sample sample::operator=(const sample &ob) {
/* If the target memory is not large enough
then allocate new memory. */
cout << "operator= strlen(ob.s): " << strlen(ob.s) << " ,strlen(s): " << strlen(s) << endl;
if(strlen(ob.s) > strlen(s)) {
cout << "operator= Larger memory of target object. Deleting current...\n";
delete [] s;
s = new char[strlen(ob.s)+1];
}
strcpy(s, ob.s);
return *this;
}
// Return an object of type sample.
sample input() {
char instr[80];
static sample str;
cout << "Enter a string: ";
cin >> instr;
str.set(instr);
return str;
}
int main() {
sample ob;
// assign returned object to ob
ob=input(); // This is now OK
ob.show();
return 0;
}
However I do not get why TWO times copy constructor is called.
(output once code is ran)
Normal constructor: s:
Normal constructor: s:
Enter a string: Hello
Copy constructor: ob.s: Hello ,strlen(ob.s): 5
operator= strlen(ob.s): 5 strlen(s): 0
operator= Larger memory of target object. Deleting current...
Copy constructor: ob.s: Hello ,strlen(ob.s): 5
s: Hello, Freeing s
s: Hello, Freeing s
Hello
s: Hello, Freeing s
s: Hello, Freeing s
I know it is called when input() function returns, and create temporary object (by calling copy constructor), but I do not get why second time since, as much as I know (but maybe I am wrong) copy constructors are NOT called for assignment operations, but it looks like, despite of that, when return *this; is called (when overloaded operator returns value), copy constructor is called?
What did I missed?
Thankx
The code is really terrible. Not to mention other bugs, here is why copy constructor is called twice.
First time it's called when an object is returned from input() since it's static and returned by value, so no RVO can be applied.
The second call happens as a result of return *this; in operator=() because for some reason it's returning an object also by value:
sample operator=(const sample &ob);
// ^^^