Nithin Chandy
Nithin Chandy

Reputation: 707

Accessing map of class A from class B

I have two classes class A and class B. Class A has a map of type map<int,int>.

In class A, i have the following definition,

   typedef std::map<int, int> mymap;

    mymap MYMAP;

    A A_OBJ;

    // did some insert operations on A_OBJ's MYMAP

I also have the following function in class A that when invoked by B will return A's MYMAP as a copy to class B.

A::mymap A::get_port(){

   // Returns A's map
   return this -> MYMAP;

}

In class B,

void B::initialize_table(){

     A::mymap port_table = A_OBJ.get_port();

     cout<< "size of ports table at A is"<<port_table.size());

}

Code got compiled with out any issue. The only problem is that even if I insert some data to A's map, B always shows that A's map has 0 elements.

I have a timer at B which calls initialize_table() every 2s and it is supposed to get the latest copy of the map from A. Not sure where it went wrong.

Any help is appreciated. Thanks.

Upvotes: 1

Views: 97

Answers (2)

erip
erip

Reputation: 16935

You're correct that you're creating a copy of the std::map. The way to fix this is by initializing a reference to the map.

Consider the following stub:

#include <iostream>
#include <map>

using my_map = std::map<int, int>;

struct A {
  A() : m() {}
  my_map& get_my_map() { return m; }
  my_map m;
};

struct B {
  B() : a() {}  
  void initialize_map_ref();
  void initialize_map_val();
  void print_index_42() { std::cout << a.get_my_map()[42] << '\n'; }
  A a;
};

void B::initialize_map_ref() {
  // notice this is a reference
  my_map& m = a.get_my_map();
  m[42] = 43;
}

void B::initialize_map_val() {
  // notice this is a copy
  my_map m = a.get_my_map();
  m[42] = 43;
}

int main() {
    B b;
    b.initialize_map_ref();
    b.print_index_42();
    return 0;
}

B::initialize_map_ref initializes a reference (i.e., a reference to the map within a), where B::initialize_map_val creates a copy and initializes the copy. The copy dies after the call, so outside of the call, m[42] == 0. The reference initialization, on the other hand, persists because you've changed a reference to the underlying object.

Ideone: With reference and with value.

Upvotes: 1

Isaac
Isaac

Reputation: 816

I suggest returning by an R-value reference for the sake of efficiency (i.e. A::mymap&& A::get_port(){return A::mymap(this -> MYMAP;) };).

I can only see your code failing in one of two circumstances:

  • you are updating A_OBJ.MYMAP after you call A_OBJ.get_port() This will cause the copy to be out of date.

  • or you are updating A_OBJ.get_port(). and then calling A_OBJ.get_port() again. This will cause the copy to be modified but the original map, to be left unmodified, resulting in the second call to A_OBJ.get_port() to not consider any changes made to the value returned by the previous.

Depending on what you want you may want to return a (const) reference to the map.

EDIT I mistakenly originally thought that A::mymap port_table = A_OBJ.get_port(); would cause two copies, but now I realize it will cause a copy and then a move, it would also do that in the rvalue case, however that is likely to introduce undefined behaviour (I think) because of returning a reference to a temporary... (originally I had it return this -> MYMAP but would be an error as it would try to bind an lvalue (this -> MYMAP) to an rvalue reference)

Upvotes: 0

Related Questions