Why "explicit" in shared_ptr's constructor?
Hello, I am a newbie user of boost. I have a question about boost::shared_ptr. Suppose you have a polimorphic list: class entity{ ...}; class simple_entity : public entity{ public: uint id; simple_entity(uint i) : id(i) {} }; int main(){ list<shared_ptr<entity> > l; ... I noticed the following code doesn't compile l.push_back(new simple_entity(1)); too bad, because it was very easy to read, and very similar to the behavior if standard pointers (not to speak about similarity to Java and C#). So I am forced to do l.push_back(shared_ptr<entity> (new simple_entity(1))); which is less readable and, IMHO, barely tolerable on the long run: too much typing. It seems that the reason is the explicit keyword in the constructor. My question is: why? what was the danger without the explicit? Thank you very much for any info, Maurizio
On Friday 28 March 2003 11:36 am, Maurizio Colucci wrote:
It seems that the reason is the explicit keyword in the constructor. My question is: why? what was the danger without the explicit?
The shared_ptr<T>(T*) takes ownership of the object referenced by the pointer. Whenever you have an implicit conversion that may take ownership, you're opening yourself up to the possibility that the programmer may not realize ownership has been transferred. For instance: void f(shared_ptr<T> x); // later on, possibly from a different programmer... T* t = new T; f(t); delete t; The programmer that writes the last three lines doesn't realize that passing a raw pointer results in the loss of ownership of the object, and now we have a double-free. The explicit construction makes the programmer think about the effects of calling a constructor, so this error is much less likely. Even worse, consider trying to update some code that used to use raw pointers to use shared_ptrs. Errors like the above would be common, but wouldn't be found at compile time. Doug
Maurizio Colucci wrote:
Hello,
I am a newbie user of boost.
I have a question about boost::shared_ptr. Suppose you have a polimorphic list:
class entity{ ...};
class simple_entity : public entity{ public: uint id; simple_entity(uint i) : id(i) {} };
int main(){ list<shared_ptr<entity> > l; ...
I noticed the following code doesn't compile
l.push_back(new simple_entity(1));
too bad, because it was very easy to read, and very similar to the behavior if standard pointers (not to speak about similarity to Java and C#). So I am forced to do
l.push_back(shared_ptr<entity> (new simple_entity(1)));
The idiomatic way to write the above is to use a named variable: shared_ptr<entity> pe(new simple_entity(1)); l.push_back(pe); as explained in http://www.boost.org/libs/smart_ptr/shared_ptr.htm#BestPractices If you want to save typing, consider adding static shared_ptr<simple_entity> create(int id) { shared_ptr<simple_entity> ps(new simple_entity(id)); return ps; } to simple_entity, allowing you to write l.push_back(simple_entity::create(1)); If entity objects are always supposed to live on the heap, you now have the option to make the simple_entity constructor private or protected, leaving 'create' as the only way to obtain a simple_entity.
participants (3)
-
Douglas Gregor
-
Maurizio Colucci
-
Peter Dimov