c++ translate from dynamic allocation to references - c++

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();
}

Related

Should I delete pointer from `new` passed to a function which makes into a `shared_ptr`?

In the following code example:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo *foo){
auto my_foo = std::shared_ptr<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(new Foo());
return 0;
}
Do I need to clean up the pointer created in main() by the bar.addFoo(new Foo) call, or will this be taken care of by Bar which creates a shared_ptr of it? My understanding is that auto my_foo = std::shared_ptr<Foo>(foo); will use the copy constructer to copy this pointer into my_foo leaving the original one dangling, is that correct?
The very idea of a constructor taking a raw pointer is to pass the ownership to std::shared_ptr. So, no, you don't have to delete a raw pointer passed to std::shared_ptr. Doing this will lead to a double deletions, which is UB.
Note that in general passing a raw pointer is dangerous. Consider the following more generalized example:
void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}
If an exception is throw before my_foo is constructed, foo will leak.
If you have no special reason to pass a raw pointer, consider the following alternative:
class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};
int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}
Here you pass arguments (if you have any) to construct Foo inside addFoo() instead of constructing Foo before invoking addFoo().
Perfect forwarding of args... could be used if it is needed:
template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}
The code you wrote is correct. But in modern C++, you should not be using raw pointers, new and delete unless you have to interoperate with code that does. If you can help it (and if question comments are any indication, you can), use smart pointers all the way through:
#include <iostream>
#include <memory>
class Foo {};
class Bar {
public:
void addFoo(std::unique_ptr<Foo> foo) {
auto my_foo = std::shared_ptr<Foo>(std::move(foo));
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_unique<Foo>());
return 0;
}
Above, the addFoo member function receives the pointer as a unique_ptr, and uses std::move to transfer ownership of the pointer from the unique_ptr to the shared_ptr without copying the referent; after constructing the shared_ptr, the unique_ptr is left in an empty state. You could also have addFoo receive a shared_ptr directly, or construct the object in-place inside the member function, as in Evg’s answer.
Using unique_ptr instead of a raw pointer makes it clear that the method intends to take ownership of the allocation, and encourages callers to use smart pointers themselves, making it less likely they will forget to delete their allocations later.
A raw pointer does not manage end of life, but a shared pointer does. When you create a shared pointer from a raw pointer, the shared pointer takes ownership of the object. That means that the object will be destroyed when the last shared pointer pointing to it will go out of scope.
In your code, my_foo takes ownership of the object created with new Foo(), goes out of scope when addFoo returns, and as it contains the only shared reference, correctly destroys the object.
The correct, c++ way to do this, would be the following:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo foo){
auto my_foo = std::make_shared<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(Foo());
return 0;
}
This avoids any raw pointers or naked new, and is totally exception safe. Also, std::make_shared introduces some performance benefits.
One confusing thing here is that the code seems to be unnecessarily copy the Foo object, however, since C++17, due to Return Value Optimization, (RVO), you are guaranteed to have no copies at all (when passing Foo as an argument to addFoo).
You can create the shared pointer with make_shared. If you want to construct Foo in main (e.g. because you have the paramters available there), then use make_shared at the point of construction and pass the shared_ptr on.
#include <iostream>
class Foo{
~Foo() { std::cout << "Foo destructed" << std::endl; }
};
class Bar{
public:
void addFoo(std::shared_ptr<Foo> foo){
auto my_foo = foo;
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_shared<Foo>());
return 0;
}
delete also calls your destructor. You can test, whether the shared pointer destructs your object or whether a delete is needed by printing out a message.

How can you re-assign (a.k.a set) class member that is unique_ptr?

class A {};
class B{
unique_ptr<A> upA;
public:
B() : upA(make_unique<A>()) {}
void set(A a){
upA.reset(move(a)); //error
//upA.reset(a); //error
//upA = move(a); //error
}
};
How can you re-assign (a.k.a set) class member that is unique_ptr?
It depends on what you want to do. Do you want to invoke operator= on the object managed by upA? If so:
*upA = a;
Do you want to accept a new unique_ptr and take ownership of it? If so:
void set(std::unique_ptr<A> a){
upA = move(a);
}
unique_ptr<A> upA;
so this is a unique (smart) pointer to an A located somewhere - fine so far.
B() : upA(make_unique<A>()) {}
OK, we initialize our pointer to point at a new, dynamically-allocated A - looks reasonable.
void set(A a){
upA.reset(move(a));
but now you want to point your smart pointer - which is responsible for managing the lifetime of the object it points to - at a local instance of A? That doesn't make sense for two reasons:
your smart pointer manages a pointer, and you're passing it an (lvalue reference to) a local object. You could convert this to a pointer by writing &a, but this still has the problem that:
your local variable a will go out of scope when the function returns, leaving your smart pointer with a dangling, invalid address to attempt to manage.
When you call B::set, what is supposed to happen? You need to decide what it's intended to do from the caller's perspective. Either:
// transfer control of the caller's A to B
void B::set(std::unique_ptr<A> a) { upA = move(a); }
or
// take control of the caller's allocated but unmanaged A
void B::set(A *a) { upA.reset(a); }
// not recommended - keep everything managed by unique_ptr if at all possible
or
// copy the caller's A into B's existing A
void B::set(A const &a) { *upA = a; }
// called as
b.set(my_local_a);
or
// move the caller's temporary A into B's existing A
void B::set(A &&a) { *upA = move(a); }
// called with an explicit move
b.set(move(my_local_a));
// or with a prvalue
b.set(A{});

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

How to keep the dynamic type of an object allocated on the stack?

Suppose I have:
class A { };
class B : public A { };
A f() {
if (Sunday())
return A;
else
return B;
}
Obviously this doesn't work since A's copy constructor would be called. Is there anyway to return stack allocated object without losing it's type?
I've tried using std::shared_ptr<A> but it got me into another issue since std::shared_ptr<B> isn't std::shared_ptr<A>.
It is not immediately possible to return a stack-allocated (i.e. local) object out of the function that created that object. Local objects are destroyed on function return. You can hide/obfuscate the actual nature of the object's allocation by using various "smart pointers" and similar techniques, but the object itself should be allocated dynamically.
Other that that, as long as the local object lifetime rules are obeyed, polymorphism for local objects works in exactly the same way as it works for any other objects. Just use a pointer or a reference
A a;
B b;
A *p = Sunday() ? &a : &b;
// Here `*p` is a polymorphic object
Pointer p in the above example remains valid as long as the local object lives, which means that you cannot return p from a function.
Also, as you see in the example above, it unconditionally creates both objects in advance, and then chooses one of the two while leaving the second one unused. This is not very elegant. You cannot create different versions of such object in different branches of if statement for the very same reasons for which you cannot return a local object from a function polymorphically: once the local block that created the object is complete, the object is destroyed.
The latter problem can be worked around by using a raw buffer and manual in-place construction
alignas(A) alignas(B) char object_buffer[1024];
// Assume it's big enough for A and B
A *p = Sunday() ? new(buffer) A() : new (buffer) B();
// Here `*p` is a polymorphic object
p->~A(); // Virtual destructor is required here
but it does not look pretty. A similar technique (involving copying of the buffer) can probably be used to make local polymorphic objects survive block boundaries (see #Dietmar Kühl's answer).
So, again, if you want to create only one object of the two and have your object to survive block boundaries, then immediate solutions put local objects are out of the question. You will have to use dynamically allocated objects.
It's not possible because of slicing. Use std::unique_ptr instead. You won't lose the dynamic type, but it will be accessible only through the interface of A.
The easiest approach is certainly to use a suitable smart pointer, e.g., std::unique_ptr<A>, as the return type and to allocate the object on the heap:
std::unique_ptr<A> f() {
return std::unique_ptr<A>(Sunday()? new B: new A);
}
For the approach returning a std::unique_ptr<A> which may point to a B, it is necessary that A has a virtual destructor as otherwise the code may result in undefined behavior when the std::unique_ptr<A> actually points to a B object. If A doesn't have a virtual destructor and can't be changed, the problem can be avoided by using a suitable std::shared_ptr<...> or by using a suitable deleter with the std::unique_ptr<...>:
std::unique_ptr<A, void(*)(A*)> f() {
if (Sunday()) {
return std::unique_ptr<A, void(*)(A*)>(new B, [](A* ptr){ delete static_cast<B*>(ptr); });
}
else {
return std::unique_ptr<A, void(*)(A*)>(new A, [](A* ptr){ delete ptr; });
}
}
If you don't want to allocate the objects on the heap, you can use a holder type which stores a union with A and B which is then appropriately constructed and destructed (the code below assumes that the copy of A or B won't throw an exception; if necessary, suitable move construction and move assignment can be added):
class holder {
bool is_b;
union {
A a;
B b;
} element;
public:
holder(): is_b(Sunday()) {
if (this->is_b) {
new(&this->element.b) B();
}
else {
new(&this->element.a) A();
}
}
holder(holder const& other) { this->copy(other); }
void copy(holder const& other) {
this->is_b = other.is_b;
if (this->is_b) {
new(&this->element.b) B(other.element.b);
}
else {
new(&this->element.a) A(other.element.a);
}
}
~holder() { this->destroy(); }
void destroy() {
if (this->is_b) {
this->element.b.~B();
}
else {
this->element.a.~A();
}
}
holder& operator= (holder const& other) {
this->destroy();
this->copy(other);
return *this;
}
operator A const&() const { return this->is_b? this->element.b: this->element.a; }
operator A&() { return this->is_b? this->element.b: this->element.a; }
};

create an instance for a pointer in other scopes

I have two methods to create an instance for a pointer.
But one of them will fail.
class A {
public:
int num;
};
void testPointer1(A* a){
a = new A();
a->num = 10;
}
A* testPointer2(){
A* a = new A();
a->num = 10;
return a;
}
void testPointer() {
A* a1 = NULL;
testPointer1(a1); // this one fails
//cout << a1->num << endl; // segmentation fault
A* a2 = NULL;
a2 = testPointer2();
cout << a2->num << endl;
}
why is testPointer1 wrong?
The syntax is valid, but it doesn't do what you want because testPointer1() is operating on a copy of the pointer, not the actual pointer itself. So when you assign the address to the newly allocated object, it gets assigned to the copy, not to the original a1 pointer.
Because of this, the address is lost and you get a memory leak. Also, since the original a1 pointer was never modified in the first place, you attempted to dereference a null pointer, which is a bad thing.
I'd say testPointer2() is the better way to do it, but if you want testPointer1() to work, try this:
void testPointer1(A*& a)
{
a = new A();
a->num = 10;
}
The parameter type indicates "a reference to a pointer to A." That way, instead of a copy of the pointer being passed, a reference to the original pointer will be passed. A C++ reference is an alias to another object. So whatever you do on the alias, it gets performed on the original object.
Extra notes:
Note that the parentheses in new A(); are actually significant and their presence or absence makes a difference.
Also note that you must manually delete all new'ed objects after you're done with them, or you will get a leak. Typically you would wrap the pointer in its own class and implement RAII or use a smart pointer such as Boost's smart pointers or auto_ptr, for proper memory management and exception safety.
If you're going to set the value of num on initialization, why not create a constructor?
class A
{
public:
A(int n) : num(n) {}
int GetNum() const { return num; }
private:
int num;
};
void testPointer1(A*& a)
{
a = new A(10);
}
A* testPointer2()
{
return new A(10);
}
// auto_ptr example, see link in second note above
std::auto_ptr<A> testPointer3()
{
return auto_ptr<A>(new A(10));
}
The testPointer1 functions works on a copy of the provided pointer : modifications to a in testPointer1 are not reflected to the caller.
It's exactly like in this simpler example :
void testInt1(int i)
{
i++;
}
void testInt()
{
int i = 0;
testInt1(i);
// i is still 0
}
If you want the change in testInt1 to be reflected to the caller, you have to pass either a pointer or reference to i (and not just the value of i). The same solution can be applied to your specific case, though one could argue that pointers to pointer and references to pointer are not really a best practice.
Is this homework ?
This seems to be obvious:
formal parameters are saved on the stack & restored after method/function call.
then whatever f(type x), manipulating x inside the function/method won't change it's value outside of the function.
even if type is a pointer type.
the only way to make x change inside a function is to tell it is modifiable through references or pointer to type.
in your case :
A* a1 =NULL
call to your method won't change value of a1 outside of testPointer1
so a1 will still be NULL after the call.