C++ strange parameter passing

I got a strange behavior while i was giving parameters. The header of my method is:

class Acceptability {
  public:
    Graph* G;                               
    std::unordered_set<node>* community;    
    std::unordered_set<node>* shell;        
  public:
    Acceptability(Graph& G, std::unordered_set<node>& community,
                  std::unordered_set<node>& shell);
    virtual ~Acceptability();
    virtual double getValue(node v) = 0;
};
class NodeClusterSimilarity: public Acceptability {
  public:
    NodeClusterSimilarity(Graph& G, std::unordered_set<node>& community,
                          std::unordered_set<node>& shell);
    virtual ~NodeClusterSimilarity(); 
    virtual double getValue(node v);
};

The constructors of both classes are the following:

GreedyCommunityExpansion::Acceptability::Acceptability(
    Graph& G, std::unordered_set<node>& community,
    std::unordered_set<node>& shell) {
  this->G = &G;
  this->community = &community;
  this->shell = &shell;
}
GreedyCommunityExpansion::NodeClusterSimilarity::NodeClusterSimilarity(
    Graph& G, std::unordered_set<node>& community,
    std::unordered_set<node>& shell)
  : Acceptability(G, community, shell) {
}

While testing my implementation, I create an object of type NodeClusterSimilarity with community {0} and shell {1,2,3}. Then i call the method getValue() and the surprise was: size of the community after passing the parameters is 1 (hurraaaaaaas!!!) but size of the shell was 0 :(( [the expected value is obviously 3]

Can any one tell me, what's going wrong?

Upvotes: 1

Views: 128

Answers (1)

Alexander Kondratskiy
Alexander Kondratskiy

Reputation: 4275

I have a feeling you created community {0} and shell {1,2,3} in-place when testing. i.e.

NodeClusterSimilarity similarity( graph, {0}, {1,2,3} );

In that case you're taking the addresses of temporary rvalues, that are deallocated by the time you call getValue(). You have two options:

  • community and shell have to outlive your NodeClusterSimilarity instance. Basically have them as separate variables on the stack before calling the constructor.
  • Make the members be const &, if you're not modifying them, and they should bind to the rvalues and keep them alive for the lifetime of Acceptability

Concretely for the second point:

class Acceptability {
  public:
    Graph const& G;
    std::unordered_set<node> const& community;
    std::unordered_set<node> const& shell;
  public:
    Acceptability(Graph const& G, std::unordered_set<node> const& community,
                  std::unordered_set<node> const& shell);
    virtual ~Acceptability();
    virtual double getValue(node v) = 0;
};

Upvotes: 1

Related Questions