Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a std::shared_ptr in assignment operators

Tags:

c++

c++11

I'm creating my own custom Filter class for use in boost::filtered_graph. The WeightMap concept must have a default constructor, copy constructor, and assignment operator.

I've created the class below, which has a std::shared_ptr private member. My question is how I'm supposed to write the assignment operator. The copy constructor wasn't a problem, but the assignment operator doesn't work.

class BFDMFilter
{
private:
const BGraph* m_battlemap;
const std::shared_ptr<MoveAbility> m_mv_ab;

public:
BFDMFilter() : m_battlemap(nullptr), m_mv_ab() { }
BFDMFilter(const BGraph* bmap, std::shared_ptr<MoveAbility> mv) : m_battlemap(bmap), m_mv_ab(mv) { }

BFDMFilter(const BFDMFilter& filter) : m_battlemap(filter.m_battlemap), m_mv_ab(filter.m_mv_ab) { }
BFDMFilter& operator=(const BFDMFilter& filter) 
{
  if(this != &filter)
  {
m_battlemap = filter.m_battlemap;
m_mv_ab = filter.m_mv_ab;
  }

  return *this;
}

bool operator()(const Edge& edge) const 
{ 
  Tile::TileEdge path = (*m_battlemap)[edge];

  return m_mv_ab->CanMove(path.TerrainType()) > 0.0;
}

bool operator()(const Vertex& vertex) const 
{ 
  Tile tile = (*m_battlemap)[vertex];

  return m_mv_ab->CanMove(tile.TerrainType()) > 0.0;
}
};

Which then gives me a compile error:

error: passing ‘const std::shared_ptr<momme::battle::MoveAbility>’ as ‘this’ argument of ‘std::shared_ptr<_Tp>& std::shared_ptr<_Tp>::operator=(std::shared_ptr<_Tp>&&) [with _Tp = momme::battle::MoveAbility, std::shared_ptr<_Tp> = std::shared_ptr<momme::battle::MoveAbility>]’ discards qualifiers [-fpermissive]

I understand why; the assignment operator modifies the reference count of the shared_ptr when it does the assignment, so that it can keep track of how many open references there are. But then, how do I write the assignment operator? std::weak_ptr has the same behavior, and if I make the reference non-const, then the boost library complains that the function is deleted.

like image 881
Brad Avatar asked Mar 03 '13 22:03

Brad


People also ask

What does shared_ptr get () do?

A shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), the dereference and the comparison operators.

How do I assign a shared pointer?

Like the unique_ptr, shared_ptr is also defined in the <memory> header in the C++ Standard Library. Because it follows the concept of shared ownership, after initializing a shared_ptr you can copy it, assign it or pass it by value in function arguments. All the instances point to the same allocated object.

Can we move shared_ptr?

By moving the shared_ptr instead of copying it, we "steal" the atomic reference count and we nullify the other shared_ptr . "stealing" the reference count is not atomic, and it is hundred times faster than copying the shared_ptr (and causing atomic reference increment or decrement).

When should I use shared_ptr?

Use this option when the implied or explicit code contract between the caller and callee requires that the callee be an owner. Pass the shared_ptr by reference or const reference. In this case, the reference count isn't incremented, and the callee can access the pointer as long as the caller doesn't go out of scope.


1 Answers

There doesn't seem to be any reason from your code to declare m_mv_ab as

const std::shared_ptr<MoveAbility> m_mv_ab;

which is the smart-pointer version of:

MoveAbility * const m_mv_ab;

(constant pointer to non-constant MoveAbility)

If you don't want to modify the pointed-to MoveAbility object and want it to be const, you should do:

std::shared_ptr<const MoveAbility> m_mv_ab;

which is the smart-pointer version of:

const MoveAbility * m_mv_ab;

(non-constant pointer to constant MoveAbility)

To make this a bit more intuitive you can use const as a suffix always and always read right-to-left, except that std::shared_ptr<X> is read "(smart) pointer to X":

std::shared_ptr<MoveAbility> const m_mv_ab; // const ptr to non-const MoveAbility
MoveAbility * const m_mv_ab; // const ptr to non-const MoveAbility

std::shared_ptr<MoveAbility const> m_mv_ab; // non-const ptr to const MoveAbility
MoveAbility const * m_mv_ab; // non-const ptr to const MoveAbility

but most people use const as a prefix whenever possible, which makes it confusing.

like image 194
Stephen Lin Avatar answered Nov 08 '22 09:11

Stephen Lin