I have a class, its object will be used by another class as following
class A
{
public:
void F() {...}
};
class B
{
public:
void G() { m_a->F(); ...} // use A's function
private:
A* m_a;
};
Thus it is wrong to call B::G() before the assignment of pointer m_a. Is this acceptable design? Or there is a better way to do it.
The question comes from developing a GUI application. I have a window under the main window to show some basic information of current operation, such as what is happening, how long does it take, and so on. I put this window as a singleton for easy access by the operations which may scatter anywhere, and find the code crashes when closing the GUI application. The crash is due to the window is deleted after the deletion of GUI application (such as qApp in Qt). I then just put a reference pointer of the window in the singleton. And when the window is constructed, I set the reference pointer. The deletion of the window is controlled by the main window. Thus the above mentioned crash problem is solved. But if other developer uses the singleton before the window is constructed, the code will crash too. Any good way to solve it? Or we can just accept it because it is developer's mistake to use it before constructing? Thanks a lot!
Invoking function G() may result in Undefined Behavior if m_a is not initialized, so you want to make sure that that's never the case. You have to change your code to make it look a bit like this:
class B
{
public:
B() : m_a(nullptr) { } // m_a always initialized!
bool G()
{
if (m_a == nullptr) return false; // No Undefined Behavior!
m_a->F(); // This call is safe now
...
return true;
}
private:
A* m_a;
};
And by the way, in general you should use smart pointers (choose the type which realizes the appropriate ownership semantics) rather than raw pointers, unless you have a good reason to do that. This would even save you from manual initialization (assuming shared ownership here):
#include <memory>
class B
{
public:
bool G()
{
if (m_a == nullptr) return false; // No Undefined Behavior!
m_a->F(); // This call is safe now
...
return true;
}
private:
std::shared_ptr<A> m_a; // Automatically initalized to nullptr
};
You have to use the member initializer list to initialize m_a rather than assign it.
It ensures you don't have to bother about getting m_a assigned before calling other functions.
Depending on your expected usage of the class, this can be an acceptable practice, but if you do that, you better change B::G() to check the pointer first:
void G() { if (m_a) m_a->F(); ...}
And make sure to initialize m_a in all constructors, at least to a null pointer if you don't currently have a real A to point at.
Related
I have an object that has different constructors. Now I want to add another constructor that based on arbitrary data will try to process that data and call the correct constructor.
AFAIK there are two ways to do it:
static function that returns the created object
static *A from_data(/arbitrary data/);
create a private "init" function that is called by constructors
But I am wondering what are the problems and potential pitfalls of using a placement new on this using the desired constructor. So the code would be:
#include <new>
struct A
{
/*different constructors*/
A(int i) {};
A(double d) {};
A(/*large set of data*/)
{
/*large set of data gets processed and depending on the processing a different constructor gets called*/
this->~A(); //deletes current object
if (true) {
new (this) A(1); //reconstructs object calling the correct constructor for the data
} else {
new (this) A(1.0); //reconstructs object calling the correct constructor for the data
}
};
};
int main(int argc, char* argv[])
{
A a;
}
You want a compile time decision (choice of constructor to delegate to) from run-time information (result of processing a data set).
That means that what you directly want, cannot be done.
But you can use your idea of a static member function that returns the created object, except that instead of A* it should return A, or else a smart pointer.
Re the other suggested solution,
” create a private "init" function that is called by cosntructors
… that doesn't solve the stated problem, and it's a generally bad idea.
Re
” what are the problems and potential pitfalls of using a placement new on this
Well, it's not code you can rely on. I believe it's Undefined Behavior because at the point where the object self-destroys it's not completely initialized. If it should turn out that it's technically well defined for the case at hand, it's not code that you would want to rely on. And in a setting with possible maintenance, someone stumbling on this code would have to replace it rather than wasting time trying to prove UB or not. Just Say No™ to the dark corners of the language.
I briefly considered spending some time trying to figure out whether the shown example results in undefined behavior, or not. But I quickly decided that this is irrelevant, a waste of time, and is completely beside the point because the current C++ standard has a perfectly well-defined, clean mechanism to do exactly the same thing, and it would be more productive to focus my answer on that, instead.
I'm referring to delegating constructors, of course:
class A {
public:
A(int n) {
// whatever
}
A(const char *p, double z)
: A( /* some formula that calculates an int value goes here */ )
{
}
};
The current C++ standard specifies a well-defined way for one constructor to delegate the actual job of constructing and initializing an instance of the class by invoking a different constructor.
Note that this doesn't mean that one constructor gets to execute arbitrary code, before deciding to invoke the delegated-to constructor. The delegation must occur as the very first order of business, where you normally see the initialization section of a constructor; where you see things like the superclasses' constructors, if any.
Only after the delegated-to constructor returns, does the delegated-from constructor have an option of running more code of its own, to finish the job.
But this is just a minor inconvenience, easily addressed with just a little bit of coding:
class A {
public:
A(int n) {
// whatever
}
A(const char *p, double z)
: A(figure_out_an_int_value_from_p_and_z(p, z))
{
}
private:
static int figure_out_an_int_value_from_p_and_z(const char *p, double z)
{
int a_very_complicated_value;
// Some complicated code that computes a_very_complicated_value.
return a_very_complicated_value;
}
};
I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.
I m writing a library.
WITHOUT using smart pointer. Is it this class safe enough to emulate retain/release behaviour?
Or is there any library already doing things like this?
class FooBase {
private:
std::atomic<uint32_t> m_retainCount;
public:
FooBase()
{
m_retainCount = 1;
};
virtual ~FooBase()
{
assert(m_retainCount == 0); // Prevent from direct delete without release()
//clean-up if any
};
void *release()
{
m_retainCount--;
if (!m_retainCount)
delete this;
return this;
};
void *retain()
{
m_retainCount++;
return this;
};
};
Imagine if your thread gets swapped right after the branch in release and before the call to delete.
Another thread could come and request a retain, therefore obtaining a pointer to a soon to be deleted object.
To answer the second part, std::shared_ptr is thread-safe. It has the additional benefit of being able to use non-portable tricks internally because it's formally part of the compiler.
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
A question about boost::shared_ptr here:
I have 3 Classes.
A is some kind of Main class which is responsible to manage everything.
B is a class which just has functions to do some work.
Dispatcher is just a class which wraps around a seperate thread, which gets the work from Instaces of Bdone in this thread.
So it is kinda working like this: A has an instance of Dispatcher. Now on occassion A generates an instance of B and passes it to the dispatcher.
The important part is, that B needs to call A::callback() when it's done. This is why B gets a reference to A in it's constructor ( see code below )
A.hpp
class A : public boost::enable_shared_from_this<A>
{
public:
A();
void sendB();
void callback();
private:
Dispatcher m_Dispatcher;
};
B.hpp
class B
{
public:
B(boost::shared_ptr<A> ptr);
boost::shared_ptr<A> m_PointerToA;
/* Some other functions */
};
Dispatcher.hpp
class Dispatcher
{
public:
void run();
void dispatch(boost::shared_ptr<B> b);
private:
void doWork();
boost::thread m_Thread;
};
A.cpp
A::A()
{
m_Dispatcher.run();
}
void A::sendB()
{
boost::shared_ptr ptr_B;
ptr_B.reset(new B(this->shared_from_this);
m_Dispatcher.dispatch(ptr_B);
}
B.cpp
B::B(boost::shared_ptr<A> ptr) :
: m_PointerToA(ptr)
{
}
main_example.cpp
int main()
{
A instanceA;
while(true)
{
instanceA.sendB();
/* Do some other stuff */
}
return 0;
}
So my question is:
Is it reasonable to use boost::shared_ptr for this purpose?
I am not sure if the shared_ptr is the right thing to go here. My problem is, that I don't know what happens exactly when I call the constructor from B and pass it the this pointer. Now according to shared_ptr I would assume that m_PointerToA takes ownership of A. But this would mean that when the work in the Dispatcher is done and my instance of B gets deleted it would also delete the reference to m_PointerToA which would actually mean it kills the object itself despite the fact there is an actual instance of A in the main loop.
Update:
Added some code and updated question itself to make it more clear.
There's nothing particular wrong with this design. However I would prefer to instead use boost::function<> & boost::bind. It gives you way better flexibility for the callback and doesn't tie B as tightly to A. Of course you still have to be vary of the usual threading caveats.
Yes, it is okay to just copy/assign a shared_ptr, it will only increase the reference count.
In your example, shared_from_this() will create a (here: temporary) shared_ptr from the weak_ptr that is hold by this (ref count 1), so when you assign/copy-construct m_PointerToA, the reference count will increase temporarily to 2 before the ctor returns and the temporary object will be destroyed, decreasing the reference count to 1 again (the shared_ptr is "aware" of the one instance in your B object).
So, yes, if B is deleted, it will destroy A in this case (as the reference count drops to 0).
Your concern
This would mean if my Instance of B is deleted, it would also delete m_PointerToA which would also kill my instance of A . Of course my original instance of A is held elsewhere.
only shows that if you plan/need/intend to keep a pointer to the instance of A for further usage, you should do so with a shared_ptr as well instead of a raw pointer. If you have control of A's interface, the easiest way would be a named constructor like this:
class A : public boost::enable_shared_from_this<A> {
public:
static boost::shared_ptr<A> create();
void initClassB();
// ....
private:
A();
A( const A & other );
A& operator=( const A & rhs );
};
boost::shared_ptr<A> A::create() {
return boost::shared_ptr<A>( new A() );
}
Then, even if your instance of B is deleted, the instance of A will still survive because the reference count of the shared_ptr is still (at least) 1.