5
votes

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.

1
I'm not sure why you need the pointer to be const...do you mean std::shared_ptr<const MoveAbility> m_mv_ab instead? Do you want the std::shared_ptr itself const or the object it's pointing at to be const? - Stephen Lin
You can't do assignment with any const data member. This isn't specific to shared_ptr. - juanchopanza

1 Answers

12
votes

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.