So say I have an object, say A, like this
class A {
private:
int x;
public:
A(){};
~A(){};
void sayA() {
std::cout << "A" << std::endl;
}
};
Now If I have a vector of pointers to A
std::vector<A *> As;
can I push back new instances of A to the vector while at the same time accessing the sayA method at the same time?
Like this
As.push_back(new A()->sayA());
Just to point out in this case A is not an Object I created, It's part of a graphics library
You can (ab)use emplace_back in C++17:
As.emplace_back(new A())->sayA();
but really, IMO this is more clear:
As.push_back(new A());
As.back()->sayA();
You could let sayA return a pointer to the instance. Like this:
auto sayA() {
std::cout << "A" << std::endl;
return this;
}
and then insert the instance as follows.
As.push_back((new A())->sayA());
But apart from making it work, this is awkward and hard to read. Consider using a vector of smart pointers and insert first, then call methods. If sayA is part of object construction, call it from A's constructor.
Basically yes, if you make sure that sayA() will return this, since push_back() will expect pointer to A, not void which is current return type of sayA(). And if you return any other pointer to A, then you will leak you newly allocated object since there will be no way to delete it.
BUT
Why you want to have vector of pointers to A and have headache of deleting them later if you can have just std::vector<A> As; and then you can call sayA() as other answers suggested.
Related
I want to initialize member object variables in the default constructor of the class.
Let's consider the following,
class ABC {
ABC(int A, int B) {
a = A;
b = B;
}
int a;
int b;
};
class Foo {
Foo();
ABC m_obj1;
};
From the above example, I would like to initialize "obj1" in "Foo::Foo()".
One of the restrictions I have is that I cannot do so in the initializer list, as I need to do some computation before I could initialize the member. So the option available (ASFAIK) is to do so in the body of the default constructor only.
Any inputs, how could I do this?
Edit: Restricting to C++11
Would this be a correct way,
Foo:Foo() {
int x = 10;
int y = 100;
m_Obj1(x, y); //Is this correct? <--------
}
Depending on your exact problem and requirements, multiple solutions might be available:
Option 1: Use a function to do the computations and call Foo constructor
Foo makeFoo()
{
// Computations here that initialize A and B for obj1 constructor
return Foo(A, B)
}
Option 2: Call a function that does the computations and initialize obj1 in Foo member initializer list
ABC initABC() {
// Some computations
return ABC(A, B)
}
Foo() : obj1(initABC()) {}
Option 3: Dynamically allocate obj1, for instance with a std::unique_ptr
Option 4: Use std::optional or an emulated c++11 version as shown by other answers
You simply call the base constructor inside the initializer list of the derived constructor. The initializer list starts with ":" after the parameters of the constructor. See example code!
There is no problem to call functions inside the initializer list itself.
int CallFunc1(int x) { return x*2; }
int CallFunc2(int y) { return y*4; }
class ABC {
public:
ABC(int A, int B):a{CallFunc1(A)},b{CallFunc2(B)} {
std::cout << "Constructor with " << a << " " << b << " called" << std::endl;
}
private:
int a;
int b;
};
class Foo {
public:
Foo(): obj1(1,2){}
Foo( int a, int b): obj1(a, b){}
private:
ABC obj1;
};
int main()
{
Foo foo;
Foo fooo( 9,10);
}
edit:
The best method I can think of for your case is a copy constructor, being more specific on what you need to store helps a lot since if it is just two ints inside a class dynamic allocation is not worth it, the size of the object being constructed makes a difference to what method is best, copy constructors can be slower with much larger data types as the object has to be created twice: once when it is automatically constructed in the parent objects constructor and again when a temporary object is created and all the values have to be copied, which can be slower then dynamically allocating if the size is larger.
As far as I'm aware all objects in a class are automatically initialized/allocated in the constructor so sadly dynamic memory use may be your best bet here.
If you are fine with having the object initialized but empty so you know it is not 'ready' yet you can later fill it with useful data when you would have wanted to initialize it. This can be done with default constructors that set the things inside the object to null values or something similar so you know the object hasn't been properly initialized yet. Then before using the object you can check whether it has been initialized by checking for the null values or by having put a bool in the object that tells you whether it is initialized. Dynamically allocated would still be better in my opinion and makes the code look cleaner overall as all you need to store is a null pointer until the object is needed and then allocated and set to the pointer. It is also very easy to check if the pointer is equal to nullptr to know the state of your object.
Dynamically allocating memory may be a hassle since you have to make sure to get rid of memory leaks and it is slightly slower than using the stack, but it is a necessary skill for c++ since the stack is not enough when making programs that use more than the few available megabytes of data on the stack so if you are doing this simply to avoid the hassle I recommend learning it properly. It would be nice if you could be more specific about what kind of object you want to do this with or if you just want an answer that works for most cases.
eg:
*ABC obj1 = nullptr;
...object is needed
obj1 = new(ABC(constructor stuff));
...obj1 isn't needed
delete obj1;
or c++ automatically deletes it when the program closes.
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 can I pass a std::unique_ptr into a function? Lets say I have the following class:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
The following does not compile:
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
return 0;
}
Why can I not pass a std::unique_ptr into a function? Surely this is the primary purpose of the construct? Or did the C++ committee intend for me to fall back to raw C-style pointers and pass it like this:
MyFunc(&(*ptr));
And most strangely of all, why is this an OK way of passing it? It seems horribly inconsistent:
MyFunc(unique_ptr<A>(new A(1234)));
There's basically two options here:
Pass the smart pointer by reference
void MyFunc(unique_ptr<A> & arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
}
Move the smart pointer into the function argument
Note that in this case, the assertion will hold!
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(move(ptr));
assert(ptr == nullptr)
}
You're passing it by value, which implies making a copy. That wouldn't be very unique, would it?
You could move the value, but that implies passing ownership of the object and control of its lifetime to the function.
If the lifetime of the object is guaranteed to exist over the lifetime of the call to MyFunc, just pass a raw pointer via ptr.get().
Why can I not pass a unique_ptr into a function?
You cannot do that because unique_ptr has a move constructor but not a copy constructor. According to the standard, when a move constructor is defined but a copy constructor is not defined, the copy constructor is deleted.
12.8 Copying and moving class objects
...
7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;
You can pass the unique_ptr to the function by using:
void MyFunc(std::unique_ptr<A>& arg)
{
cout << arg->GetVal() << endl;
}
and use it like you have:
or
void MyFunc(std::unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
and use it like:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));
Important Note
Please note that if you use the second method, ptr does not have ownership of the pointer after the call to std::move(ptr) returns.
void MyFunc(std::unique_ptr<A>&& arg) would have the same effect as void MyFunc(std::unique_ptr<A>& arg) since both are references.
In the first case, ptr still has ownership of the pointer after the call to MyFunc.
Why can I not pass a unique_ptr into a function?
You can, but not by copy - because std::unique_ptr<> is not copy-constructible.
Surely this is the primary purpose of the construct?
Among other things, std::unique_ptr<> is designed to unequivocally mark unique ownership (as opposed to std::shared_ptr<> ).
And most strangely of all, why is this an OK way of passing it?
Because in that case, there is no copy-construction.
As MyFunc doesn't take ownership, it would be better to have:
void MyFunc(const A* arg)
{
assert(arg != nullptr); // or throw ?
cout << arg->GetVal() << endl;
}
or better
void MyFunc(const A& arg)
{
cout << arg.GetVal() << endl;
}
If you really want to take ownership, you have to move your resource:
std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));
or pass directly a r-value reference:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr doesn't have copy on purpose to guaranty to have only one owner.
Since unique_ptr is for unique ownership, if you want to pass it as argument try
MyFunc(move(ptr));
But after that the state of ptr in main will be nullptr.
To piggyback the existing answers, C++ smart pointers are strongly related to the concept of ownership. Your code should clearly express your inensions related to passing or not the ownership to another component, i.e. function, thread or so, that's why there are unique, shared and weak pointers. The unique pointer already suggests that only one component has the ownership of that pointer at one moment, so that unique ownership cannot be shared, only moved. Namely the owner that currently owns the pointer will destroy it at its own will when getting out of context, usually at the end of the block or in a destructor. Passing an object to another function might imply sharing or moving the ownership. If you are sure that the owner don't get out of the context while calling the function by reference, calling by reference is possible, but it's just ugly. It adds some preconditions and postconditions and will increase the immobility of your code while it also breaks the smartness of the pointer which tuns into a more or less raw pointer. For example, changing the "function" to start and execute its own stuff in another thread is not longer possible. As passing by reference is still an option in some very contained parts of your code, i.e. looking for saving extra overhead of moving back and forth from unique to shared pointers, I would highly avoid it, especially in public interfaces.
Passing std::unique_ptr<T> as value to a function is not working because, as you guys mention, unique_ptr is not copyable.
What about this?
std::unique_ptr<T> getSomething()
{
auto ptr = std::make_unique<T>();
return ptr;
}
this code is working
I need to store references to instances of derived classes in C++. I considered using a vector of shared_ptrs to the base class (for it needs to hold different types of derived classes), however, it's important that the container holds the original pointers, which is not the case with vectors (or other stl containers), if I'm not mistaken. Is there a way to do this in native C++, or do I have to use special containers like Boost's ptr_vector?
EDIT: This is my test code:
class Foo
{
public:
Foo() {}
virtual ~Foo() {}
virtual void set_x(int i) = 0;
};
class Bar : public Foo
{
public:
Bar() {}
void set_x(int i)
{
this->x = i;
}
int x;
};
int main()
{
Bar bar;
// ptr
std::cout << &bar << "\n";
std::vector<Foo*> foos;
foos.push_back(&bar);
// different ptr value
std::cout << &foos[0] << "\n";
foos[0]->set_x(1);
// however, changes are made
std::cout << bar.x;
return 0;
}
Thanks in advance,
jena
In your example above, what you are printing out is the address of the pointer not the value of the pointer.
Instead of:
// different ptr value
std::cout << &foos[0] << "\n";
Do
// different ptr value
std::cout << foos[0] << "\n";
Aside from that your vector<Foo*> will work just fine.
You can create a std::vector<foo*>, which will hold any pointers to foo that you hand to it. It won't make any attempt to delete those pointers on destruction, which may or may not be what you want, but it will hold exactly the values you pass in.
You can also create an std::vector< shared_ptr<foo> >, which will hold pointers that will be released once there are no dangling copies of the shared_ptr floating around. Those will also hold the "original" foo* you passed in; you can get it again by using the shared_ptr::get() method.
The only time you wouldn't see exactly the same pointer as your derived object is if you're using multiple inheritance of classes, and your base classes include data. Because a foo* would end up, in that case, pointing to the "foo" part of the data, which wouldn't necessarily be at the "root" of the object.
If you use shared_ptr as your container member, the pointer in each member will retain access to the original object instance. You can get a copy of a shared_ptr at any point after container housekeeping, but the original object will still be its target.
For a simpler solution you might use boost::ptr_vector, provided none of your pointers occur twice in the container - that scenario would introduce tricky resource management complexity and point you back to shared_ptr.
I have a Foo object, and a std::list holding instances of it. My problem is that when I add a new instance to the list, it first calls the ctor but then also the dtor. And then the dtor on another instance (according to the this pointer).
A single instance is added to the list but since its dtor (along with its parents) is called, the object cant be used as expected.
Heres some simplified code to illustrate the problem:
#include <iostream>
#include <list>
class Foo
{
public:
Foo()
{
int breakpoint = 0;
}
~Foo()
{
int breakpoint = 0;
}
};
int main()
{
std::list<Foo> li;
li.push_back(Foo());
}
When you push_back() your Foo object, the object is copied to the list's internal data structures, therefore the Dtor and the Ctor of another instance are called.
All standard STL container types in C++ take their items by value, therefore copying them as needed. For example, whenever a vector needs to grow, it is possible that all values in the vector get copied.
Maybe you want to store pointers instead of objects in the list. By doing that, only the pointers get copied instead of the object. But, by doing so, you have to make sure to delete the objects once you are done:
for (std::list<Foo*>::iterator it = list.begin(); it != list.end(); ++it) {
delete *it;
}
list.clear();
Alternatively, you can try to use some kind of 'smart pointer' class, for example from the Boost libraries.
You are creating a temporary Foo here:
li.push_back( Foo() )
push_back copies that Foo into its internal data structures. The temporary Foo is destroyed after push_back has been executed, which will call the destructor.
You will need a proper copy constructor that increases some reference count on the class members that you do not want to destroy early -- or make it private to force yourself on the pointer solution.
Use this object to understand:
class Foo
{
public:
Foo(int x): m_x(x)
{
std::cout << "Constructed Object: " << m_x << ")\n";
}
Foo(Foo const& c): m_x(c.m_x+100)
{
std::cout << "Copied Object: " << m_x << ")\n";
}
~Foo()
{
std::cout << "Destroyed Object: " << m_x << ")\n";
}
};
The First main
std::list<Foo*> li;
li.push_back(Foo(1));
Here we create a temporary Foo object and call push_back(). The temporary object gets copied into the list and the function returns. On completion of this statement the temporary object is then destroyed (via the destructor). When the list is destroyed it will also destroy all the obejcts it contains (Foo is an object with a destructor so destruction includes calling the destructor).
So you should see somthing like this:
Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101
In the second example you have:
std::list<Foo*> li;
li.push_back(new Foo(1));
Here you dynamically create an object on the heap. Then call the push_back(). Here the pointer is copied into the list (the pointer has no constructor/destructor) so nothing else happens. The list now contains a pointer to the object on the heap. When the function returns nothing else is done. When the list is destroyed it destroys (note the subtle difference betweens destroy and delete) the object it contains (a pointer) but a pointer has no destructor so nothing happens any you will leak memory.
So you should see somthing like this:
Constructed Object: 1
What actually happens here is that you store a copy of the passed object in the list, because you're sending it by value instead of by reference. So the first dtor that is called is actually called on the object you pass to the push_back method, but a new instance had been created by then and it is now stored in the list.
If you don't want a copy of the Foo object to be created, store pointers to Foo objects in the list instead of the objects themselves. Of course when doing it you will have to properly release memory on destruction of the list.
Making the list holding pointers instead of instances solves the problem with the destructor being called. But I still want to understand why it happens.
#include <iostream>
#include <list>
class Foo
{
public:
Foo()
{
int breakpoint = 0;
}
~Foo()
{
int breakpoint = 0;
}
};
int main()
{
std::list<Foo*> li;
li.push_back(new Foo());
}