Using RAII to simplify passing objects to other objects without copy - c++

extern class objx;
class Someclass
{
public:
Someclass();
void bar(objx);
objx &om;
};
void foo()
{
Someclass c;
objx o;
c.bar(o);
}
void Someclass::bar(objx& op)
{
//Save op in some local privatefield for later use
om = op; //Here there should not be a copy;
}
Above code is wrong right? Because when o goes out of scope in foo() it is destructed. Is there a way not to copy o into a new object in bar? For example using bar(objx&& op) so we don't have to copy object or use smart pointers and for sure avoiding new/delete? And when bar() returns op would go out of scope and object gets destroyed.
[EDIT]
I could use a pointer instead. But the caller should keep track of the lifetime of the object. That is what I want to avoid.
[EDIT2]
The question is this: Is there a mechanism to keep a local variable alive as long as its reference is passed by reference to other functions (scopes)?
[EDIT4]
This code achieves same functionality using pointers:
#include <sstream>
class Someclass
{
public:
Someclass() { }
void bar(std::stringstream *);
std::stringstream *om;
};
void Someclass::bar(std::stringstream* op)
{
om = op;
}
int main()
{
Someclass c;
std::stringstream o;
c.bar(&o);
return 0;
}

Above code is wrong right? Because when o goes out of scope in foo() it is destructed.
It depends on what "Save op in some local privatefield for later use" means. Making a copy is correct. Referring to the object would not be.
Is there a way not to copy o into a new object in bar?
You can move into a new object instead.
The receiver class is already instantiated.
Option 1: Don't do that.
Option 2: Assign the value member.

From the responses you kindly provided I concluded that it can be done if the passing object has the move semantics implemented in it.

Related

_CrtIsValidHeapPointer(block) when using std::shared_ptr

I am trying to create and use a std::shared_ptr within a class function whose constructor takes in a std::shared_ptr private data member (of the same class) and another std::shared_ptr created with a raw pointer to the class object (this).
Whenever I call the function that creates the std::shared_ptr (foo), I get a _CrtIsValidHeapPointer(block) assertion. I'm assuming it has something to do with the way in which the shared_ptr is being deleted, but I can't seem to figure it out, and I've searched all over the Internet. Maybe I'm not fully understanding how shared_ptrs work.
Is it not acceptable to create a shared_ptr using the this pointer, or a pre-existing shared_ptr data member?
class Containing_Class;
class Some_Class
{
};
class Set_Value_Command
{
public:
Set_Value_Command(std::shared_ptr<Some_Class> ptr1, std::shared_ptr<Containing_Class> ptr2)
: _ptr1(ptr1), _ptr2(ptr2)
{}
private:
std::shared_ptr<Some_Class> _ptr1;
std::shared_ptr<Containing_Class> _ptr2;
};
class Containing_Class
{
public:
Containing_Class(std::shared_ptr<Some_Class> psc)
: _psc(psc)
{}
void foo()
{
std::shared_ptr<Set_Value_Command> command = std::make_shared<Set_Value_Command>(_psc, std::shared_ptr<Containing_Class>(this));
}
private:
std::shared_ptr<Some_Class> _psc;
};
Here is the main() function. When foo() is called, the assertion happens:
int main()
{
std::shared_ptr<Some_Class> some_class = std::make_shared<Some_Class>();
Containing_Class cc(some_class);
cc.foo();
}
Is it not acceptable to create a shared_ptr using the this pointer
Not by itself, no. And doing so in your example is very bad. Your Containing_Class object is being created in automatic memory of main()'s local stack frame, and thus will be destroyed automatically when it goes out of scope when main() exits. But creating a shared_ptr from this inside of the Containing_Class object will assign ownership of this to the shared_ptr, which will then try to delete this when there are no more shared_ptr references to this. delete'ing an object that was not created with new to begin with is undefined behavior, and is why you are crashing with an error about an invalid heap pointer.
In order to allow shared_ptr to refer to this, Containing_Class would need to derive from std::enable_shared_from_this, and this would have to point at an object that is created dynamically and owned by a shared_ptr. Only then can Containing_Class call its inherited shared_from_this() method to get a shared_ptr to itself.
For example:
class Containing_Class;
class Some_Class
{
};
class Set_Value_Command
{
public:
Set_Value_Command(std::shared_ptr<Some_Class> ptr1, std::shared_ptr<Containing_Class> ptr2)
: _ptr1(ptr1), _ptr2(ptr2)
{}
private:
std::shared_ptr<Some_Class> _ptr1;
std::shared_ptr<Containing_Class> _ptr2;
};
class Containing_Class : public std::enable_shared_from_this<Containing_Class>
{
public:
Containing_Class(std::shared_ptr<Some_Class> psc)
: _psc(psc)
{}
void foo()
{
std::shared_ptr<Set_Value_Command> command = std::make_shared<Set_Value_Command>(_psc, shared_from_this());
}
private:
std::shared_ptr<Some_Class> _psc;
};
int main()
{
auto some_class = std::make_shared<Some_Class>();
auto cc = std::make_shared<Containing_Class>(some_class);
cc->foo();
}
With the code
std::shared_ptr<Containing_Class>(this)
you introduce a second *this owner, i.e. command is the owner of a shared pointer that controls cc life. That is the first issue. Yet another, following issue is that command is pointing to a stack object.
Usually *this is owned by someone and passing ownership to another owner never works.
The current code is impossible to fix due to lack of the code aim.

Reference and pointer in polymorphism

Base abstract class:
class Satellite
{
public:
Satellite();
virtual void center()=0;
virtual ~Satellite(){}
};
First derived class
class Comm_sat:public Satellite
{
public:
Comm_sat();
void center() override{cout << "comm satellite override\n";}
};
Second derived class
class Space_station:public Satellite
{
public:
Space_station();
void center() override{cout << "space station override\n";}
};
Pointer version of the functions
void f(Satellite* ms){
ms->center();
delete ms;
}
int main()
{
Comm_sat* cs = new Comm_sat;
Space_station* ss = new Space_station;
f(cs);
f(ss);
}
The objects created using new in main() are properly destroyed in f(), right?
Reference version of the functions
void f(Satellite& ms){
ms.center();
}
int main()
{
Comm_sat cs;
Space_station ss;
f(cs);
f(ss);
}
Is the reference version better?
Besides, I try to use unique_ptr, however, I get errors
void f(Satellite* ms){
ms->center();
}
int main()
{
unique_ptr<Comm_sat> cs{new Comm_sat};
unique_ptr<Space_station> ss{new Space_station};
f(cs);
f(ss);
}
Error: cannot convert std::unique_ptr<Comm_sat> to Satellite* for argument 1 to void f(Satellite*)
Error: type class std::unique_ptr<Comm_sat> argument given to delete, expected pointer delete cs;
Same error for the other derived class.
Is the reference version better?
Yes, although a better way to put this would be "the pointer version is worse". The problem with the pointer version is that you pass it a valid pointer, and get a dangling pointer when the function returns. This is not intuitive, and leads to maintenance headaches when someone modifies your code thinking that you have forgotten to delete cs and ss in the main, not realizing that f deletes its argument.
The version that uses a reference is much better in this respect, because the resources are managed automatically for you. Readers of your code do not need to track the place where the memory of cs and ss gets released, because the allocation and release happen automatically.
I try to use unique_ptr, however, I get errors
There is no implicit conversion from std::unique_ptr<T> to T*. You need to call get() if you want to pass a raw pointer:
f(cs.get());
f(ss.get());
The objects created using new in main() are properly destroyed in f(), right?
They're destroyed, and cleaned up correctly, yes. "Properly" is a stretch though, since all this manual-new-and-delete-raw-pointers stuff is poor style.
The reason unique_ptr isn't working for you is that ... it's a unique_ptr, not a raw pointer. You can't just pass it as a raw pointer.
Try
void f(Satellite* ms){
ms->center();
}
// ...
f(cs.get());
or better, unless you really need to pass nullptr sometimes,
void f(Satellite& ms){
ms.center();
}
// ...
f(*cs);
or best of all, since you don't show any reason to require dynamic allocation at all:
void f(Satellite& ms);
// ...
{
Comm_sat cs;
f(cs);
} // no new, no delete, cs goes out of scope here

c++ translate from dynamic allocation to references

I have following code:
class A{
public:
virtual do_something() = 0;
}
class B : public A{
public:
virtual do_something() override;
}
void use_a(A *a){
if (a){
a->do_something();
delete a;
}
}
use_a( new B() );
How this can be translated to references?
Notice do_something() is not const method.
I thought it can be something like this:
void use_a(A &&a){
a->do_something();
}
use_a( B() );
but someone told me this is bad style and must be avoided.
Rvalue references have move sematics. That does not work well when moving B as A.
Use lvalue reference:
void use_a(A &a);
B b;
use_a(b);
or a template:
template <typename T>
void use_a(T &&a);
or, if it doesn't need to be a reference, a smart pointer:
void use_a(std::unique_ptr<A> a);
void use_a(std::shared_ptr<A> a);
Quite simply you convert from a pointer to a reference by providing a concrete instance, i.e. you dereference:
void f(int& i);
f(*(new int)); // do not do this!
The problem is that raw pointers in C++ are precisely that - they do not have automatic lifetime scope, and by converting to an lvalue reference, you have suggested a contract that the instance is concrete and should not be destroyed by the receiver.
int* ptr = new int;
f(ptr);
delete ptr; // otherwise it leaked
Modern C++ uses RAII to provide controlled automatic lifetime management, and C++11 introduced unique_ptr and shared_ptr for handling pointers. With C++14 we also have the mechanisms to avoid raw pointers entirely.
std::unique_ptr<int> ptr = std::make_unique<int>(/* ctor arguments here */);
f(ptr.get());
// now when ptr goes out of scope, deletion happens automatically.
See also http://en.cppreference.com/w/cpp/memory/unique_ptr
Only one std::unique_ptr should have the address of a given allocation at any time (it assumes ownership and will delete the allocation on exiting scope if it's not released).
For a ref-counted pointer: http://en.cppreference.com/w/cpp/memory/shared_ptr
--- EDIT ---
Based on the OPs comments:
Firstly note that
Pair p = { "one", "two" };
// and
Pair p("one", "two");
Pair p{"one", "two"};
are synonymous, in all cases they create a stack-local variable, p, by allocating stack space and calling Pair::Pair("one", "two") to construct a Pair object there.
Remember, however, that this is a stack variable - it has an automatic lifetime and will expire at the end of the current scope.
{ Pair p{"one", "two"}; list_add(list, p); } //p is destroyed
In theory, you can replace this with
list_add(list, Pair{"one", "two"});
But what matters is whether list_add expects you to keep the object around until you remove it from the list... That is often what a list-based function that takes a pointer is expecting. If it takes a non-const reference, it may do the same.
To answer your original post::
struct A { virtual void doSomething() {} };
struct B : public A { virtual void doSomething() override() {} };
void useDoSomethingInterface(A& a) {
a.doSomething();
}
int main() {
A a;
B b;
useDoSomethingInterface(a);
useDoSomethingInterface(b);
}
consider the following:
void list_add(IList& list, Pair& pair) {
pair.next = list.head;
list.head = &pair; // << BAD NEWS
}
void badness(IList& list) {
list_add(list, Pair("hello", "world"));
}
void caller() {
IList list;
badness(list);
// list.head now points to a destroyed variable on the stack
C-pointers in C++ are raw, machine level pointers. They don't ref count. And C++ object instances have a fixed well defined lifetime: till the end of the scope.
However, if list_add is taking its data by value
void list_add(IList& list, Pair pair)
Then we'll be ok. The temporary Pair we create will have to be copied once to create pair and then copied again into the list, which is a shame but at least it won't crash.
your code is a bit unsafe.
first, what if a is null? you didn't check it.
second, what if a points to a stack-object or data-segment-object? you'll have unexpected behaviour (=crash on most of the OS).
if your object has to be dynamically alocated, just use std::shared_ptr
void use_a(std::shared_ptr<A>& a){
a->do_something();
}

How do I prevent the creation of temporary objects?

I have code similar to this:
MyClass createInstance()
{
MyClass t;
t.setValue(20);
return t;
}
int main()
{
MyClass primary;
primary.setValue(30);
primary = createInstance();
}
My problem is that createInstance() creates a temporary that is deleted later. In my case, it doesn't use RVO, I have to use The Rule of Three (because my class has a pointer to data members), and I have to do a deep copy of Megabytes of data.
I wonder what's the best way to prevent the creation of a temporary?
Furthermore, I have this MyClass as a member of another class and I would like to prevent the indirection of a pointer and the requirement to manually delete it in the destructor of my parent class.
For example, I could use pointers instead (which would require me to explicitly call the destructor:
MyClass *createInstance()
{
MyClass *t = new MyClass();
t->setValue(20);
return t;
}
int main()
{
MyClass *primary = new MyClass();
primary->setValue(30);
delete primary;
primary = createInstance();
}
Or I could use a member function:
void MyClass::createNewInstance()
{
~MyClass();
init();
setValue(20);
}
int main()
{
MyClass primary;
primary.setValue(30);
primary.createNewInstance();
}
Or I could disallow Assignment/Copying in general:
void MyClass::createInstance()
{
setValue(20);
}
int main()
{
MyClass *primary = new MyClass();
primary->setValue(30);
delete primary;
primary = new MyClass();
primary->createInstance();
}
Am I missing something?
You can't (N)RVO copy into a pre-existing object. The optimization is all about using another freshly created object instead of copying, but in this case the compiler can't guarantee that the assignment object doesn't leave some of the existing state alone (for example).
I would expect that MyClass primary(createInstance()); would enable NRVO for you.
If you really need to assign from a create function your choices are at least two: You can create a temporary and then swap, avoiding the data copy. Alternately with C++11 you could move into the existing object.
Just like what paddy said, how do you know it's not using RVO?
The compiler will do many thing to optimize your code, if it's not in debugging mode.
But, in your creatInstance function, you create a local object, and call a member function on it. The calling of the member function ( t->setValue(20) ) makes it difficult to be optimized, because the compiler will think, the local object is more useful than just an return value. Clearly, we know the local t can be optimized out, but the compiler may not be able to analyze this from its context.
And, by the meaning of "creatInstance", it seems that you just want creat an instance and return it. So, if your constuctor allows to set the value directuly, you can use the RVO:
MyClass creatInstance()
{
return MyClass(20); // if your constuctor makes it possible
}
then, your code will be optimized to this:
// C++ psuedocode
void creatInstance(MyClass* ptr)
{
new (ptr) MyClass(20);
}
int main()
{
MyClass primary;
primary.setValue(30);
// primary = createInstance();
MyClass __temp; // default constructor not called!
creatInstance(&__temp);
primary.operator=(__temp);
// destruct the __temp
}
You may think, it still has to creat temporary object __temp and destroy it , yes, but in your original code, you will creat two temporary object and destroy them, one in your main stack frame, one in your creatInstance function's stack frame.
If you can not sustain the cost of creating temporary object and those stuff, I think you can just change your idea to this:
void modifyInstance(Myclass& objToBeModified)
{
objToBeModified.setValue(20);
// do any change
}
and call it by : modifyInstance ( primary );
by this way, the temporary object creation is definitely prevented!
After all, you just want to change the primary by calling a function, why not writting it directly like above?

Using class pointers vs instance

What I don't understand is what is the difference between using a pointer to a class and generating a new instance of it. It's just for performance? Here I made a class and made m the pointer to the class and n the instance of the class.
And another question: can i make a pointer the class and use another constructor? like myClass* p(7); p->afis(); ?
#include <iostream>
using namespace std;
class myClass
{
int a;
public:
myClass(void);
myClass(int);
void afis();
~myClass(void);
};
myClass::myClass(void)
{
a = 5;
}
myClass::myClass(int nr)
{
a = nr;
}
void myClass::afis()
{
cout << a;
}
myClass::~myClass()
{
}
int main()
{
myClass* m; //<--
m->afis();
myClass n(7); //<--
n.afis();
cin.get();
}
myClass* m;
is just an pointer to the type myClass it does not point to any valid object, dereferecing such a pointer is Undefined Behavior.
An Undefined Behavior means that your program is invalid and it may seem to work or it may crash or it may show any weird behavior, all safe bets are off. So just because your program works does not mean it is safe and it will always work.
To write a valid program you will have to make the pointer point to a valid object.
For example:
myClass obj;
myClass*m = &obj;
In the second case:
myClass n(7);
It creates an object n of the type myClass by calling the constructor of myClass which takes one argument of the type int.
This is a valid way of creating an object.
can i make a pointer the class and use another constructor
Making a pointer doesn't call a constructor. The pointer is uninitialized until you set it to the address of some object (maybe a brand new object created with new).
myClass* m; //<--
m->afis();
This is undefined behavior, you have a wild pointer because m hasn't been initialized.
Better:
std::unique_ptr<myClass> m(new myClass(constructor, args, here));
m->afis();