Why doesn't shared_ptr permit direct assignment - c++

So when using shared_ptr<Type> you can write:
shared_ptr<Type> var(new Type());
I wonder why they didn't allow a much simpler and better (imo):
shared_ptr<Type> var = new Type();
Instead to achieve such functionality you need to use .reset():
shared_ptr<Type> var;
var.reset(new Type());
I am used to OpenCV Ptr class that is a smart pointer that allows direct assignment and everything works fine

The syntax:
shared_ptr<Type> var = new Type();
Is copy initialization. This is the type of initialization used for function arguments.
If it were allowed, you could accidentally pass a plain pointer to a function taking a smart pointer. Moreover, if during maintenance, someone changed void foo(P*) to void foo(std::shared_ptr<P>) that would compile just as fine, resulting in undefined behaviour.
Since this operation is essentially taking an ownership of a plain pointer this operation has to be done explicitly. This is why the shared_ptr constructor that takes a plain pointer is made explicit - to avoid accidental implicit conversions.
The safer and more efficient alternative is:
auto var = std::make_shared<Type>();

The issue with allowing a raw pointer to be implicitly converted into a std::shared_ptr can be demonstrated with
void foo(std::shared_ptr<int> bar) { /*do something, doesn't matter what*/ }
int main()
{
int * bar = new int(10);
foo(bar);
std::cout << *bar;
}
Now if the implicit conversion worked the memory bar points to would be deleted by the shared_ptr destructor at the end of the foo(). When we go to access it in std::cout << *bar; we now have undefined behavior as we are dereferencing a deleted pointer.
In your case you create the pointer directly at the call site so it does not matter but as you can see from the example it can cause problems.

Allowing this allows you to call functions with pointer arguments directly, which is error prone because you're not necessarily aware at call site that you're creating a shared pointer from it.
void f(std::shared_ptr<int> arg);
int a;
f(&a); // bug
Even if you disregard this, you create the invisible temporary at the call site, and creating shared_ptr is quite expensive.

I wonder why they didn't allow a much simpler and better...
Your opinion will change as you become more experienced and encounter more badly written, buggy code.
shared_ptr<>, like all standard library objects is written in such as way as to make it as difficult as possible to cause undefined behaviour (i.e. hard to find bugs that waste everyone's time and destroy our will to live).
consider:
#include<memory>
struct Foo {};
void do_something(std::shared_ptr<Foo> pfoo)
{
// ... some things
}
int main()
{
auto p = std::make_shared<Foo>(/* args */);
do_something(p.get());
p.reset(); // BOOM!
}
This code cannot compile, and that's a good thing. Because if it did, the program would exhibit undefined behaviour.
This is because we'd be deleting the same Foo twice.
This program will compile, and is well-formed.
#include<memory>
struct Foo {};
void do_something(std::shared_ptr<Foo> pfoo)
{
// ... some things
}
int main()
{
auto p = std::make_shared<Foo>(/* args */);
do_something(p);
p.reset(); // OK
}

Why [doesn't] shared_ptr permit direct assignment [copy initialization]?
Because it is explicit, see here and here.
I wonder what the rationale [is] behind it? (From a comment now removed)
TL;DR, making any constructor (or cast) explicit is to prevent it from participating in implicit conversion sequences.
The requirement for the explicit is better illustrated with the shared_ptr<> is an argument for a function.
void func(std::shared_ptr<Type> arg)
{
//...
}
And called as;
Type a;
func(&a);
This would compile, and as written and is undesired and wrong; it won't behave as expected.
It gets further complicated with adding user defined (implicit) conversions (casting operators) into the mix.
struct Type {
};
struct Type2 {
operator Type*() const { return nullptr; }
};
Then the following function (if not explicit) would compile, but offers a horrible bug...
Type2 a;
func(a);

Related

C++11 best practice to use rvalue

I am new to C++11. In fact until recently, I programmed only using dynamic allocation, in a way similar to Java, e.g.
void some_function(A *a){
a->changeInternalState();
}
A *a = new A();
some_function(a);
delete a;
// example 2
some_function( new A() ); // suppose there is **no** memory leak.
Now I want to reproduce similar code with C++11, but without pointers.
I need to be able to pass newly created class class A directly to function useA(). There seems to be a problem if I want to do so with non-const normal reference and It works if I do it with rvalue reference.
Here is the code:
#include <stdio.h>
class A{
public:
void print(){
++p; // e.g. change internal state
printf("%d\n", p);
}
int p;
};
// normal reference
void useA(A & x){
x.print();
}
// rvalue reference
void useA(A && x){
useA(x);
}
int main(int argc, char** argv)
{
useA( A{45} ); // <--- newly created class
A b{20};
useA(b);
return 0;
}
It compiles and executes correctly, but I am not sure, if this is the correct acceptable way to do the work?
Are there some best practices for this kind of operations?
Normally you would not design the code so that a temporary object gets modified. Then you would write your print function as:
void useA(A const & x){
x.print();
}
and declare A::print as const. This binds to both rvalues and lvalues. You can use mutable for class member variables which might change value but without the object logically changing state.
Another plan is to keep just A &, but write:
{ A temp{45}; useA(temp); }
If you really do want to modify a temporary object, you can write the pair of lvalue and rvalue overloads as you have done in your question. I believe this is acceptable practice for that case.
The best thing about C++11 move semantics is that most of the time, you get them "for free" without having to explicitly add any &&s or std::move()s in your code. Usually, you only need to use these things explicitly if you're writing code that does manual memory management, such as the implementation of a smart pointer or a container class, where you would have had to write a custom destructor and copy constructor anyway.
In your example, A is just an int. For ints, a move is no different from a copy, because there's no opportunity for optimization even if the int happens to be a disposable temporary. Just provide a single useA() function that takes an ordinary reference. It'll have the same behavior.

Return value copying issue (to improve debug timing) -- What's the solution here?

The most interesting C++ question I've encountered recently goes as follows:
We determined (through profiling) that our algorithm spends a lot of time in debug mode in MS Visual Studio 2005 with functions of the following type:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
As most of you probably know, the return here calls a copy constructor to pass out a copy of retval and then the destructor on retval. (Note: the reason release mode is very fast for this is because of the return value optimization. However, we want to turn this off when we debug so that we can step in and nicely see things in the debugger IDE.)
So, one of our guys came up with a cool (if slightly flawed) solution to this, which is, create a conversion operator:
MyClass::MyClass(MyClass *t)
{
// construct "*this" by transferring the contents of *t to *this
// the code goes something like this
this->m_dataPtr = t->m_dataPtr;
// then clear the pointer in *t so that its destruction still works
// but becomes 'trivial'
t->m_dataPtr = 0;
}
and also changing the function above to:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
// note the ampersand here which calls the conversion operator just defined
return &retval;
}
Now, before you cringe (which I am doing as I write this), let me explain the rationale. The idea is to create a conversion operator that basically does a "transfer of contents" to the newly constructed variable. The savings happens because we're no longer doing a deep copy, but simply transferring the memory by its pointer. The code goes from a 10 minute debug time to a 30 second debug time, which, as you can imagine, has a huge positive impact on productivity. Granted, the return value optimization does a better job in release mode, but at the cost of not being able to step in and watch our variables.
Of course, most of you will say "but this is abuse of a conversion operator, you shouldn't be doing this kind of stuff" and I completely agree. Here's an example why you shouldn't be doing it too (this actually happened:)
void BigFunction(void)
{
MyClass *SomeInstance = new MyClass;
// populate SomeInstance somehow
g(SomeInstance);
// some code that uses SomeInstance later
...
}
where g is defined as:
void g(MyClass &m)
{
// irrelevant what happens here.
}
Now this happened accidentally, i.e., the person who called g() should not have passed in a pointer when a reference was expected. However, there was no compiler warning (of course). The compiler knew exactly how to convert, and it did so. The problem is that the call to g() will (because we've passed it a MyClass * when it was expecting a MyClass &) called the conversion operator, which is bad, because it set the internal pointer in SomeInstance to 0, and rendered SomeInstance useless for the code that occured after the call to g(). ... and time consuming debugging ensued.
So, my question is, how do we gain this speedup in debug mode (which has as direct debugging time benefit) with clean code that doesn't open the possibility to make such other terrible errors slip through the cracks?
I'm also going to sweeten the pot on this one and offer my first bounty on this one once it becomes eligible. (50 pts)
You need to use something called "swaptimization".
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
int main() {
MyClass ret;
f().swap(ret);
}
This will prevent a copy and keep the code clean in all modes.
You can also try the same trick as auto_ptr, but that's more than a little iffy.
If your definition of g is written the same as in your code base I'm not sure how it compiled since the compiler isn't allowed to bind unnamed temporaries to non-const references. This may be a bug in VS2005.
If you make the converting constructor explicit then you can use it in your function(s) (you would have to say return MyClass(&retval);) but it won't be allowed to be called in your example unless the conversion was explicitly called out.
Alternately move to a C++11 compiler and use full move semantics.
(Do note that the actual optimization used is Named Return Value Optimization or NRVO).
The problem is occuring because you're using MyClass* as a magic device, sometimes but not always. Solution: use a different magic device.
class MyClass;
class TempClass { //all private except destructor, no accidental copies by callees
friend MyClass;
stuff* m_dataPtr; //unfortunately requires duplicate data
//can't really be tricked due to circular dependancies.
TempClass() : m_dataPtr(NULL) {}
TempClass(stuff* p) : m_dataPtr(p) {}
TempClass(const TempClass& p) : m_dataPtr(p) {}
public:
~TempClass() {delete m_dataPtr;}
};
class MyClass {
stuff* m_dataPtr;
MyClass(const MyClass& b) {
m_dataPtr = new stuff();
}
MyClass(TempClass& b) {
m_dataPtr = b.m_dataPtr ;
b.m_dataPtr = NULL;
}
~MyClass() {delete m_dataPtr;}
//be sure to overload operator= too.
TempClass f(void) //note: returns hack. But it's safe
{
MyClass retval;
// some computation to populate retval
return retval;
}
operator TempClass() {
TempClass r(m_dataPtr);
m_dataPtr = nullptr;
return r;
}
Since TempClass is almost all private (friending MyClass), other objects cannot create, or copy TempClass. This means the hack can only be created by your special functions when clearly told to, preventing accidental usage. Also, since this doesn't use pointers, memory can't be accidentally leaked.
Move semantics have been mentioned, you've agreed to look them up for education, so that's good. Here's a trick they use.
There's a function template std::move which turns an lvalue into an rvalue reference, that is to say it gives "permission" to move from an object[*]. I believe you can imitate this for your class, although I won't make it a free function:
struct MyClass;
struct MovableMyClass {
MyClass *ptr;
MovableMyClass(MyClass *ptr) : ptr(ptr) {}
};
struct MyClass {
MyClass(const MovableMyClass &tc) {
// unfortunate, we need const reference to bind to temporary
MovableMyClass &t = const_cast<MovableMyClass &>(tc);
this->m_dataPtr = t.ptr->m_dataPtr;
t.ptr->m_dataPtr = 0;
}
MovableMyClass move() {
return MovableMyClass(this);
}
};
MyClass f(void)
{
MyClass retval;
return retval.move();
}
I haven't tested this, but something along those lines. Note the possibility of doing something const-unsafe with a MovableMyClass object that actually is const, but it should be easier to avoid ever creating one of those than it is to avoid creating a MyClass* (which you've found out is quite difficult!)
[*] Actually I'm pretty sure I've over-simplified that to the point of being wrong, it's actually about affecting what overload gets chosen rather than "turning" anything into anything else as such. But causing a move instead of a copy is what std::move is for.
A different approach, given your special scenario:
Change MyClass f(void) (or operator+) to something like the following:
MyClass f(void)
{
MyClass c;
inner_f(c);
return c;
}
And let inner_f(c) hold the actual logic:
#ifdef TESTING
# pragma optimize("", off)
#endif
inline void inner_f(MyClass& c)
{
// actual logic here, setting c to whatever needed
}
#ifdef TESTING
# pragma optimize("", on)
#endif
Then, create an additional build configurations for this kind of testing, in which TESTING is included in the preprocessor definitions.
This way, you can still take advantage of RVO in f(), but the actual logic will not be optimized on your testing build. Note that the testing build can either be a release build or a debug build with optimizations turned on. Either way, the sensitive parts of the code will not be optimized (you can use the #pragma optimize in other places too, of course - in the code above it only affects inner_f itself, and not code called from it).
Possible solutions
Set higher optimization options for the compiler so it optimizes out the copy construction
Use heap allocation and return pointers or pointer wrappers, preferably with garbage collection
Use the move semantics introduced in C++11; rvalue references, std::move, move constructors
Use some swap trickery, either in the copy constructor or the way DeadMG did, but I don't recommend them with a good conscience. An inappropriate copy constructor like that could cause problems, and the latter is a bit ugly and needs easily destructible default objects which might not be true for all cases.
+1: Check and optimize your copy constructors, if they take so long then something isn't right about them.
I would prefer to simply pass the object by reference to the calling function when MyClass is too big to copy:
void f(MyClass &retval) // <--- no worries !
{
// some computation to populate retval
}
Just simple KISS principle.
Okay I think I have a solution to bypass the Return Value Optimization in release mode, but it depends on the compiler and not guaranteed to work. It is based on this.
MyClass f (void)
{
MyClass retval;
MyClass dummy;
// ...
volatile bool b = true;
if b ? retval : dummy;
}
As for why the copy construction takes so long in DEBUG mode, I have no idea. The only possible way to speed it up while remaining in DEBUG mode is to use rvalue references and move semantics. You already discovered move semantics with your "move" constructor that accepts pointer. C++11 gives a proper syntax for this kind of move semantics. Example:
// Suppose MyClass has a pointer to something that would be expensive to clone.
// With move construction we simply move this pointer to the new object.
MyClass (MyClass&& obj) :
ptr (obj.ptr)
{
// We set the source object to some trivial state so it is easy to delete.
obj.ptr = NULL;
}
MyClass& operator = (MyClass&& obj) :
{
// Here we simply swap the pointer so the old object will be destroyed instead of the temporary.
std::swap(ptr, obj.ptr);
return *this;
}

how to call a function when auto_ptr is a parameter of it!

#include <iostream>
#include <memory>
class test
{
private:
int x , y;
public:
test(int a , int b):x(a),y(b){}
void fun()
{
std::cout<< x<<" "<<y<<" "<<std::endl;
}
};
void show(std::auto_ptr<test> t1)
{
t1->fun();
}
int main()
{
show(new test(3,4));
}
I am getting a compilation error , please tell me what's wrong in this code?Thanks in advance.
Whenever you dynamically allocate an object, you should create a named smart pointer that immediately takes ownership of the object, then use that named smart pointer. For example,
std::auto_ptr<test> ptr(new test(3, 4));
show(ptr);
You cannot pass new test(3, 4) directly to the function because std::auto_ptr objects must be explicitly constructed; it would be quite unexpected if a smart pointer took ownership of an object implicitly.
That said, this is rather unusual anyway because when you call show(), the auto_ptr is copied and when auto_ptr is "copied," the original loses ownership and the copy gains ownership (so, after show() is called, you will find that ptr no longer has ownership of the object.
James explained how to resolve the problem.
But the reason auto_ptr was designed so that you can not do this:
show(new test(3,4));
Is because this is a bad idea.
Even this (if it were allowed):
show(std::auto_ptr<test>(new test(3,4)));
Would be a bad idea.
So you ask why.
Well in the normal situation not a big deal.
Bu what happens when you have a function that takes more than one parameter.
show2(std::auto_ptr<test>(new test(3,4)), SomeObject());
Now the standard gurantees that all parameters will be fully evaluated before the call (even the construction of the auto_ptr). But it does not guarantee the evaluation order nor that the evaluation will not be interleaved.
Thus it is possible for this evaluation:
// Phsedu code for parameter evaluation
test* tmp1 = new test(3,4);
SomeObject const& tmp2 = SomeObject();
std::auto_ptr<test> const& tmp3(tmp1);
call(tmp3, tmp1)
This order is bad. Because if the constructor of SomeObject throws an exception you will leak tmp1 as it has not yet been assigned to the std::auto_ptr.
This is why we auto_ptr was designed so that you have to give it a named variable.
std::auto_ptr<test> tmp3(new test(3,4));
SomeObject tmp1;
call(tmp3, tmp1)
Now if SomObject constructor throws the test object will be tidied up.

C++ "smart pointer" template that auto-converts to bare pointer but can't be explicitly deleted

I am working in a very large legacy C++ code base which shall remain nameless. Being a legacy code base, it passes raw pointers around all over the place. But we are gradually trying to modernize it and so there are some smart pointer templates as well. These smart pointers (unlike, say, Boost's scoped_ptr) have an implicit conversion to the raw pointer, so that you can pass one of them into a routine that takes a raw pointer without having to write .get(). A big downside of this is that you can also accidentally use one in a delete statement, and then you have a double free bug, which can be a real pain to track down.
Is there a way to modify the template so that it still has the implicit conversion to the raw pointer, but causes a compile error if used in a delete statement? Like this:
#include <my_scoped_ptr>
struct A {};
extern void f(A*);
struct B
{
scoped_ptr<A> a;
B();
~B();
};
B::B()
: a(new A)
{
f(a); // this should compile
}
B::~B()
{
delete a; // this should NOT compile
}
The Standard says
The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section.
You can (ab)-use the absence of overload resolution by declaring a const version of the conversion function. On a conforming compiler that's enough to make it not work anymore with delete:
struct A {
operator int*() { return 0; }
operator int*() const { return 0; }
};
int main() {
A a;
int *p = a; // works
delete a; // doesn't work
}
Results in the following
[js#HOST2 cpp]$ clang++ main1.cpp
main1.cpp:9:3: error: ambiguous conversion of delete expression of type 'A' to a pointer
delete a; // doesn't work
^ ~
main1.cpp:2:3: note: candidate function
operator int*() { return 0; }
^
main1.cpp:3:3: note: candidate function
operator int*() const { return 0; }
^
1 error generated.
On compilers that are less conforming in that regard (EDG/Comeau, GCC) you can make the conversion function a template. delete does not expect a particular type, so this would work:
template<typename T>
operator T*() { return /* ... */ }
However, this has the downside that your smartpointer is now convertible to any pointer-type. Although the actual conversion is still typechecked, but this won't rule out conversions up-front but rather give a compile time error much later. Sadly, SFINAE does not seem to be possible with conversion functions in C++03 :) A different way is to return a private nested type pointer from the other function
struct A {
operator int*() { return 0; }
private:
struct nested { };
operator nested*() { return 0; }
};
The only problem now is with a conversion to void*, in which case both conversion functions are equally viable. A work-around suggested by #Luther is to return a function pointer type from the other conversion function, which works with both GCC and Comeau and gets rid of the void* problem while having no other problems on the usual conversion paths, unlike the template solution
struct A {
operator int*() { return 0; }
private:
typedef void fty();
operator fty*() { return 0; }
};
Notice that these workarounds are only needed for compilers that are not conforming, though.
There isn't a way to stop one and not the other. Anywhere it can be implicitly converted to a pointer for a function call, it can be implicitly converted for a delete expression.
Your best bet is to remove the conversion function. Your situation is exactly why user-defined conversion operators are dangerous and shouldn't be used often.
I'm wrong. :(
You can use a technique presented by Boost, but my concern is that you're allowing implicit conversions from a smart pointer to a raw pointer, which is generally frowned upon on. Besides, users can call delete on a pointer obtained by the -> operator, so there's really nothing you can do to prevent a determined idiot to work around whatever mechanism you come up with.
You really should just implement a get() method instead of providing operator T*() so that at least calls to delete smartptr will not compile. Non-idiots should be able to figure out that there's probably a reason why that won't work.
Yes, it's more work to type out LegacyFunc(smartptr.get()) than LegacyFunc(smartptr), but the former is preferred since it makes it explicit and prevents unexpected conversions from happening, like delete smartptr.
What if you have functions like this:
void LegacyOwnPointer(SomeType* ptr);
where the function will store the pointer somewhere? This will screw up the smart pointer, because now it's not aware that something else is owning the raw pointer.
Either way, you have some work to do. Smart pointers are like raw pointers, but they are not the same, so you can't just find-and-replace all instances of T* and replace it with my_scoped_ptr<T> and expect it to work just as well as before.
have not thought much about this but ... Can you provide an overload for operator delete which is strongly-typed for instances of your template class such that when the code is included compilation fails? if this is in your header file then implicit conversion in calls to delete should be prevented in favour of a call to your overload.
operator delete(my_scoped_ptr)
{
//... uncompilable code goes here
}
Apologies if this turns out to be a stupid idea.
I can see where you do not want to do a massive application of .get()'s. Have you ever consider a much smaller replacement of delete's?
struct A
{
friend static void Delete( A* p) { delete p; }
private:
~A(){}
};
struct B
{
};
int main()
{
delete new B(); //ok
Delete( new A ); //ok
delete new A; //compiler error
return (0);
}

Casting/dereferencing member variable pointer from void*, is this safe?

I had a problem while hacking a bigger project so I made a simpel test case. If I'm not omitting something, my test code works fine, but maybe it works accidentally so I wanted to show it to you and ask if there are any pitfalls in this approach.
I have an OutObj which has a member variable (pointer) InObj. InObj has a member function. I send the address of this member variable object (InObj) to a callback function as void*. The type of this object never changes so inside the callback I recast to its original type and call the aFunc member function in it. In this exampel it works as expected, but in the project I'm working on it doesn't. So I might be omitting something or maybe there is a pitfall here and this works accidentally. Any comments? Thanks a lot in advance.
(The problem I have in my original code is that InObj.data is garbage).
#include <stdio.h>
class InObj
{
public:
int data;
InObj(int argData);
void aFunc()
{
printf("Inside aFunc! data is: %d\n", data);
};
};
InObj::InObj(int argData)
{
data = argData;
}
class OutObj
{
public:
InObj* objPtr;
OutObj(int data);
~OutObj();
};
OutObj::OutObj(int data)
{
objPtr = new InObj(data);
}
OutObj::~OutObj()
{
delete objPtr;
}
void callback(void* context)
{
((InObj*)context)->aFunc();
}
int main ()
{
OutObj a(42);
callback((void*)a.objPtr);
}
Yes, this is safe.
A pointer to any type can be converted to a pointer to void and back again.
Note that the conversion to void* is implicit, so you don't need the cast.
What you have posted should be "safe" insofar as a non type safe operation like this can be safe. I would replace the casts you have though with static_cast instead of C style casts, because static_cast doesn't allow you to make such unsafe conversions between types. If you try to do something unsafe with static_cast the compiler will tell you instead of leaving you guessing.
(Side unrelated note: InObj's constructor should use initialization rather than assignment:
InObj::InObj(int argData) : data(argData)
{
}
)