unique_ptr and move()

When I use a unique_ptr instance, I frequently copy it around. Unique_ptr ‘s copying is actual moving.

The are different ways to code it.

  • sometimes you need to use someFunc(move(myUniquePtr));
  • sometimes you can omit move() and the semantics remain the same.

http://stackoverflow.com/questions/9827183/why-am-i-allowed-to-copy-unique-ptr has some examples. Note none of the functions have a parameter/return type showing “&&”. That’s because there is pbclone in play. The copying uses the move-constructor, which does have a && parameter.

I think some developers simply copy sample working code, without understanding why, like an ape. Some use threading constructs the same way. Nothing shame. I feel interviewers are interested in your understanding.

unique^shared^auto_ptr

unique_ptr shared_ptr auto_ptr scoped_ptr
container can put into container forbidden NO
instance field yes [1] yes ? Yes!
stack obj YES yes OK? Yes
copyable yes no. move-only releases ownership NO
as return type YES yes

[1] https://katyscode.wordpress.com/2012/10/04/c11-using-stdunique_ptr-as-a-class-member-initialization-move-semantics-and-custom-deleters/ and http://stackoverflow.com/questions/15648844/using-smart-pointers-for-class-members

shared_ptr(+unique_ptr)pbclone^pbref#Sutter

Practical question. In practice, the safe and lazy choice is pbclone. In IV, I think pbclone is “acceptable”. I feel pbref (const ref) is a risky micro-optimization, but Herb Sutter advised differently:

  • Express that a function will store and share ownership of a heap object using a by-value shared_ptr parameter
  • Use a const shared_ptr& as a parameter only if you’re not sure whether or not you’ll take a copy and share ownership. Perhaps the default choice IMO.

In my apps, the  receiving function often saves the smart_ptr in some container. Both options above actually work fine.

If you just need to access the underlying raw pointer, then Sutter said just pass in the raw pointer. I feel a pbref is also acceptable.

Smart pointer objects are designed to mimic raw pointers, which are usually passed by clone.

see http://stackoverflow.com/questions/8385457/should-i-pass-a-shared-ptr-by-reference and http://stackoverflow.com/questions/3310737/shared-ptr-by-reference-or-by-value

—-With unique_ptr, rules are simpler. Pass by clone as much as you want. It will be move-constructed. I don’t think pbref is needed.

See other posts about unique_ptr, such as https://bintanvictor.wordpress.com/2017/03/31/unique_ptr-and-move/

my simple autoPtr class template

#include <iostream>
using namespace std;

struct Dummy {
	void play() {
		cout << "play " << payload << endl;
	}
	float payload = 0.40490;
};
ostream& operator<<(ostream& os, Dummy const & d){
	os << "[ Dummy object "<<d.payload<<" ]";
	return os;
}
template<typename T> class autoPtr {
public:
	autoPtr(): autoPtr(nullptr){}
	autoPtr(T* raw): needle(raw) {
		needle = raw;
		if (raw)
			cout << "ctor called with *raw == " << *raw << endl;
	}
	autoPtr(autoPtr<T> & other) { //steal the resource
		cout << "copier called with other.real ";
		needle = other.needle;
		if (other.needle) {
			cout << "pointing to "<<*needle;
			other.needle = nullptr;
		}else {
			cout << "== nullptr";
		}
		cout << endl;
	}
	autoPtr<T> & operator=(autoPtr<T> & other) {
		if (&other == this) return *this;
		cout << "op= called ...";
		if (needle) {
			cout << " ... deleting original raw ptr *real = " << *needle;
			delete needle;
		}
		cout << endl; this->needle = other.needle;
		other.needle = nullptr;
		return *this;
	}
	T* operator->() {
		cout << "calling operator->"<<endl;
		return needle;
	}
	T& operator* () {
		cout << "dereferencing this ...";
		if (needle)
			cout << ".... *real == " << *needle << endl;
		else {
			cout << ".... returning a null ptr" << endl; throw "dereferencing a null autoPtr!"; } return *needle; //how do we return a T when real is nullptr? } void set(T * const raw) { delete this->needle;
		this->needle = raw;
	}
	~autoPtr() {
		cout << "Dtor called for *real == ";
		if (needle)
			cout << *needle;
		else
			cout << "(null ptr)";
		cout<< endl;
		delete needle;
	}
private:
	T* needle;
};
int main() {
	autoPtr<Dummy> pdummy(new Dummy);
	pdummy->play();
	autoPtr<int> p1 = (autoPtr<int>)new int(12);
	{
		autoPtr<int> p2(new int(35));
		cout << "Testing deference: *ptr == "<<*p2<< endl;
		autoPtr<int> p3(p2);
		p1 = p3;
	}
	return 0;
}

MyType a=77 what if conversion constructor is explicit

Background:

  explict MyType(int); // would disallow
  MyType a = 77;

http://en.cppreference.com/w/cpp/language/converting_constructor has a solution:

  MyType a = (MyType) 77; // Static cast would invoke the explicit conversion constructor!

Most custom types should make conversion constructors explicit to avoid hidden bugs, but smart pointer need an implicit conversion constructor, to support

  SmartPtr<int> myPtr = new int(77);

–A real example from CFM quant code

 FwdCurve::const_iterator iter = find( key ); //non-const itr

 QL_ASSERT( iter != ((FwdCurve * const) this)->end(), "not found" ); // original code probably before "explicit". 

// I had to change it to
 FwdCurve_iterator endItr = ((FwdCurve * const) this)->end();
 QL_ASSERT( iter != FwdCurve_const_iterator(endItr), "not found" ); //call the conversion ctor explicitly

factory returning a (smart) ptr

Background — This is one example of “too many variations”. A simple idea become popular. People start mix-n-match it with other ideas and create many, many interesting questions. In practice we should stick to a few best practices and avoid the hundreds of other variations.

I think it’s quite common (see [[safe c++]] P51) to have a factory function creating a heap “resource”. Given it’s on heap, factory must return the object by pointer. Easy to hit memory leak. Standard solution is return by ref count smart ptr.

Q: what if I forget to destruct the obj returned?
A: I feel it’s uncommon and unnatural. (More common to forget deletion.) Often the object returned i.e. the smart pointer object is on the stack – no way to “forget”.

Note if a raw pointer variable is on the stack, then the stack unwinding will deallocate/reclaim the memory, but won’t call delete on it!

Q: what if the object returned is saved as a field like myUmbrella.resource1
A: I feel this is fine because the myUmbrella object will be destructed by someone’s responsibility. That would automatically destruct the smart pointer field this->resource1.

Alternative to the ref count smart ptr, we can also return a scoped pointer. See [[safe c++]].

Q: what if factory need to return a pointer to stack?
A: I don’t think so. Pointee goes out of scope….
A: I feel most “resources” are represented by a heapy thingy. Alternatively, it’s also conceivable to hold a “permanent” resource like globally. Memory management is non-issue.

By the way, [[safe c++]] also mentions the __common__ pattern of a (non-factory) function returning a pointer to an existing object, rather than a “new SomeClass”. The challenges and solutions are different.