Apologies if this is a trivial problem.
I'm trying to pass a multimap that has been put together with one class in a library to another class in that library in order to further manipulate the data there.
The code relates to a GUI written by other people and the classes here relate to two different tools in the GUI.
Very roughly speaking my code and what I'm after here is like this
class A
{
private:
std::multimap<int, double> mMap;
int anInt;
double aDouble;
***some more definitions***
public:
void aFunction(***openscenegraph node, a string, and a parser function***)
{
***a few definitions are declared and initialised here
during calculations***
***some code calculating data stuff that
passes bits of that data to mMap (including information
initialised within the function)***
}
}
class B
{
public:
void bFunction(***openscenegraph node and some other data***)
{
***I want to be able to access all the data in mMap here***
}
}
Can anyone make it clear to me how I can do this, please?
Edit: Added to clarify what i'm aiming for
//Edit by Monkone
//section below is akin to what I'm trying to do
class B
{
private:
std::multimap<int, double> mMapb;
public:
std::multimap<int,double> bFunction2(A::MultiMapDataType data)
{
return mMap;
}
void bFunctionOriginal()
{
***I want to be able to access all the data in mMap here***
***i.e. mMapb.bFunction2(mMap);***
***do stuff with mMapb***
}
}
However I can't get anything to actually do something like this
I won't be needing to work on the map, only get information from it.
You could then add a function to return a const reference to the map and functions for returning const iterators to A:
class A {
public:
typedef std::multimap<int, double> intdoublemap_t;
typedef intdoublemap_t::const_iterator const_iterator;
// typedef intdoublemap_t::iterator iterator;
private:
intdoublemap_t mMap;
public:
// direct access to the whole map
const intdoublemap_t& getMap() const { return mMap; }
// iterators
const_iterator cbegin() const { return mMap.begin(); }
const_iterator cend() const { return mMap.end(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
/*
iterator begin() { return mMap.begin(); }
iterator end() { return mMap.end(); }
*/
};
Now you can iterate over the map from the outside (from B):
void bFunction(const A& a) {
for(A::const_iterator it = a.begin(); it!=a.end(); ++it) {
std::cout << it->first << " " << it->second << "\n";
}
}
Or access the map directly:
void bFunction(const A& a) {
const A::intdoublemap_t& mref = a.getMap();
//...
}
The C++ private members cannot be accessed by other (non friend) classed.
The first solution it would be to keep mMap private (not polite to work on other classes members) and offer assessors over it.
class A
{
public:
typedef std::multimap<int, double> MultiMapDataType;
private:
MultiMapDataType mMap;
***some more definitions***
public:
const MultiMapDataType& getConstMMap() const;
MultiMapDataType getMMap();
}
class B
{
public:
void bFunction(A::MultiMapDataType data)
{
***I want to be able to access all the data in mMap here***
}
void bFunction2(const A::MultiMapDataType& data)
{
***I want to be able to access all the data in mMap here***
}
}
A a;
B b;
b.bFunction(a.getMMap());
b.bFunction2(a.getConstMMap());
However, from architectural point, if you have multiple members that you need to share you should move them all in a new structure/class that encapsulates that functionality.
Related
I want to implement something like maplistner in c++ for std::map. So when a key is added or updated in std::map it should trigger a function or object.
It should be as:
class MapListener : public std::map
{
// ----- MapListener methods---
public:
// Invoked when a map entry has been inserted.
virtual void entryInserted();
// Invoked when a map entry has been updated.
virtual void entryUpdated();
// Invoked when a map entry has been removed.
virtual void entryDeleted();
};
Any help will be appreciated.
Thanks
Solution
(I am not advocating you should do this, just showing how to do so, because this sounds very much like the x-y problem to me).
template<class Key, class T, class Compare = std::less<Key>>
class EventMap final
{
public:
EventMap(): data_{}
{}
// std::map::insert looks like this:
// std::pair<iterator,bool> insert( const value_type& value );
using insert_callback = void (const value_type& inserted);
void on_insert(insert_callback* cb)
{
on_insert_ = cb;
}
// wrapped insert:
void insert(const value_type& value)
{
data_.insert(value);
if(on_insert_)
(*on_insert_)(value);
}
// TODO: add similar code for other methods w/ callbacks
private:
std::map<Key, T, Compare> data_;
insert_callback *on_insert_ = nullptr;
};
client callback:
auto on_insertion(const auto& kv)
{
std::cout << "inserted: " << kv.first << ", " << kv.second << "\n";
}
int main()
{
EventMap<std::string, std::string> map;
map.on_insert(&on_insertion);
map.insert({"123", 123}); // will call on_insertion after inserting
}
I apologise for blatantly ripping off #utnapistim solution, but the original would not compile. Nevertheless I find it interesting and would like to share working version:
#include <iostream>
#include <string>
#include <map>
template<class Key, class T, class Compare = std::less<Key>>
class EventMap final
{
public:
EventMap() : data_{}
{}
// std::map::insert looks like this:
// std::pair<iterator,bool> insert( const value_type& value );
using insert_callback = void(const std::pair<const Key, T> &inserted);
using erase_callback = void(const Key &key);
void on_insert(insert_callback* icb)
{
on_insert_ = icb;
}
void on_erase(erase_callback *ecb)
{
on_erase_ = ecb;
}
// wrapped insert:
void insert(const std::pair<const Key, T>&value)
{
data_.insert(value);
if (on_insert_)
(*on_insert_)(value);
}
// wrapped erase:
void erase(const Key &key)
{
data_.erase(key);
if (on_erase_)
(*on_erase_)(key);
}
// TODO: add similar code for other methods w/ callbacks
private:
std::map<const Key, T, Compare> data_;
insert_callback *on_insert_ = nullptr;
erase_callback *on_erase_ = nullptr;
};
int main()
{
EventMap<const std::string, std::string> map;
auto on_insert_fn = [](std::pair<const std::string, std::string> const &kv)
{
std::cout << "inserted: " << kv.first << ", " << kv.second << "\n";
};
auto on_erase_fn = [](const std::string &key)
{
std::cout << "erased: " << key << "\n";
};
map.on_insert(on_insert_fn);
map.insert({ "123", "456" }); // will call on_insert_fn after inserting
map.insert({ "786", "101112" }); // will call on_insert_fn after inserting
map.on_erase(on_erase_fn);
map.erase("123"); // will call on_erase_fn after erasing
system("pause");
return 0;
}
You absolutely don't want to have : public std::map in your class definition, because then there is no hope of keeping all of the ways of modifying the map contained.
What you will instead find is that you have one type for the client, containing the event handlers, and another type that wraps a map and delegates every action to it, plus calls the relevant handler function.
You won't be able to use this in lots of places where map would work, as to see modifications to values via iterators and operator[] you are forced to use a proxy for your reference member. Thus your iterator and const_iterator members don't satisfy ForwardIterator (and BidirectionalIterator). Thus you don't satisfy Container (and AssociativeContainer).
As an alternative to not being a Container, you could instead have a value_type of std::pair<const Key, const Value>, and simply require that modifications happen with an "erase-modify-insert" sequence.
I have a class idx_aware that goes into a container container, which wraps around a std::vector. When the class is added to container, container sets a pointer to itself in idx_aware, as well as the index of idx_aware in its internal memory storage.
The index is not going to change until the container is destroyed or idx_aware is removed; idx_aware needs to know about its container and its index, because it has some methods that require both to work.
Now this introduces the following problem: when I get a non-const reference to an idx_aware class contained in container, I could assign to it another idx_aware class, which could have a different index. The intention would be assigning all the fields and keeping the index as it is.
#include <vector>
#include <limits>
#include <iostream>
class container;
// Stores a std::size_t field, which can be set only by subclasses.
class with_idx {
std::size_t _i;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()) {}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) { _i = i; }
};
// Knows its index and its container
class idx_aware : public with_idx {
container const *_container;
int _some_field1;
float _some_field2;
public:
void foo() {
// Do stuff using _container and _i
}
private:
friend class container;
};
// Wraps around a std::vector
class container {
std::vector<idx_aware> _data;
public:
idx_aware &operator[](std::size_t idx) {
// Need non-const access to call foo
return _data[idx];
}
idx_aware const &operator[](std::size_t idx) const {
return _data[idx];
}
std::size_t add(idx_aware const &item) {
// Here it could potentially reuse a freed position
std::size_t free_slot = _data.size();
// Ensure _data is big enough to contain free_slot
if (_data.size() <= free_slot) {
_data.resize(free_slot + 1);
}
// Assign
_data[free_slot] = item;
_data[free_slot].set_idx(free_slot);
_data[free_slot]._container = this;
return free_slot;
}
};
int main() {
container c;
idx_aware an_item;
std::size_t i = c.add(an_item);
std::cout << c[i] << std::endl; // Prints 0
idx_aware another_item; // Created from somewhere else
// I want to set all the data in idx_aware, but the
// index should stay the same!
c[i] = another_item;
std::cout << c[i] << std::endl; // Prints numeric_limits<size_t>::max()
// Now container[i] is broken because it doesn't know anymore its index.
return 0;
}
One possible workaround would be to change with_idx in such a way that when set_idx is called, a flag is set that prevents assignment and copy operator to overwrite the _i property, like this:
class with_idx {
std::size_t _i;
bool _readonly;
public:
with_idx() : _i(std::numeric_limits<std::size_t>::max()), _readonly(false) {}
with_idx(with_idx const &other) : _i(other._i), _readonly(false) {}
with_idx &operator=(with_idx const &other) {
if (!_readonly) {
_i = other._i;
}
return *this;
}
operator std::size_t() const { return _i; }
protected:
void set_idx(std::size_t i) {
_i = i;
if (i != std::numeric_limits<std::size_t>::max()) {
// This has been set by someone with the right to do so,
// prevent overwriting
_readonly = true;
} else {
// Removed from the container, allow overwriting
_readonly = false;
}
}
};
This would have the consequence of returning, after assignment, a reference to an idx_aware class with unchanged index.
idx_aware ¬_in_container1 = /* ... */;
idx_aware ¬_in_container2 = /* ... */;
idx_aware &in_container = /* ... */;
not_in_container1 = in_container = not_in_container2;
// std::size_t(not_in_container_1) != std::size_t(not_in_container_2)
Is there a design pattern that can model this situation in a better way? My searches were not successful.
Are there other unwanted consequences of overriding the assignment operator in this way? The limitation I pointed out in the previous example does not look too "bad".
Is there an easier solution? I thought about writing some proxy object to replace the idx_aware & return type of operator[].
Experience tells that when C++ does not do what you intend, you are likely to be misusing OOP...
Robert's comment suggested me this solution.
Why would the contained object know about its container? To be able to perform actions such as foo and provide shorthand methods that otherwise would require to have access to the container.
Let's take this functionality away from the contained object; the contained object is just data payload. Instead, let's make operator[] return not the contained object, but some sort of iterator, a wrapper around the contained object, which knows the container and the index, and once dereferenced returns the actual contained object.
class was_idx_aware {
int _some_field1;
float _some_field2;
};
class container {
std::vector<idx_aware> _data;
public:
class idx_aware_wrapper {
container const *_container;
std::size_t _idx;
public:
idx_aware_wrapper(container const &c, std::size_t i)
: _container(&c)
, _idx(i)
{}
was_idx_aware const &operator*() const {
return _container->_data[_idx];
}
was_idx_aware &operator*() {
return _container->_data[_idx];
}
void foo() {
// Do stuff using _container and _idx.
}
};
idx_aware_wrapper operator[](std::size_t i) {
return idx_aware_wrapper(*this, i);
}
/* .... */
};
This allows quick access to any data in was_idx_aware, and the wrapper class can be augmented with all the methods that require interaction with the container. No need to store and keep indices up to date or override assignment operators.
I am wanting to make a class which allows me to lock an object from being modified. It would essentially be a template with a boolean specifying the lock state. Since it is a template, I won't know all the methods that can be called on the internal object, so I need a method to pass calls through...
template<class T>
class const_lock
{
public:
const_lock() : my_lock(false) {}
void set_const_lock(bool state) {my_lock = state;}
// HOW TO IMPLEMENT SOMETHING LIKE THESE????
//
template<typename...Args >
auto operatorANY_OPERATOR (Args...args)
{
if(my_lock != false)
throw std::exception("Objected locked to modification");
return my_value.ANY_OPERATOR(args);
}
template<typename...Args >
auto operatorANY_CONST_OPERATOR (Args...args) const
{
return my_value.ANY_CONST_OPERATOR(args);
}
template<typename...Args >
auto ANY_METHOD(Args...args)
{
if(my_lock != false)
throw std::exception("Objected locked to modification");
return my_value.ANY_METHOD(args);
}
template<typename...Args >
auto ANY_CONST_METHOD(Args...args) const
{
return my_value.ANY_CONST_METHOD(args);
}
private:
bool my_lock;
T my_value;
}
int main()
{
const_lock<std::vector<int>> v;
v.push_back(5);
v.push_back(7);
v.set_const_lock(true);
v.push_back(9); // fails compilation
std::cout << v.at(1) << std::endl; // ok
}
Any help would be appreciated. Thanks!
Edit: changed static assert to throw and exception
What you're trying to do looks rather difficult, but more importantly is over-complicated and unnecessary for what you're trying to do.
Essentially what you're trying to do (correct me if I'm wrong) is create a compile time check of whether you are supposed to able to modify an object at a given time. However, c++ already has a built in way of doing this. Simply declare or pass your object as const or const&, and the compiler will not allow you to modify non-mutable parts of the object. When you want to be able to modify it pass it without const. You can even cast it from const& to regular & when you want to go from code where you can't modify it directly to code where you can, though I don't recommend it.
edit: just saw a comment on the question about no reference arrays. Don't worry about that! The standard library has support for reference wrappers which allow you to essentially store references in arrays or anywhere else.
You can make a generic wrapper class that you can forward the function to using a lambda that captures a reference to the internal member. In this example I am just using an if statement to check if it is "locked" and if it is then we just modify a copy.
template<class T>
class const_lock
{
private:
bool my_lock;
mutable T my_value;
public:
const_lock() : my_lock(false) {}
void set_const_lock() { my_lock = true; }
template<typename F>
auto operator()(F f) const -> decltype(f(my_value))
{
if (my_lock)
{
T temp{my_value}; // make a copy
return f(temp);
}
else
return f(my_value); // modify wrraped value
}
};
int main()
{
const_lock<std::string> cl;
cl([](std::string& s) {
s = "foobar";
});
cl([](std::string& s) {
std::cout << s << std::endl;
});
cl.set_const_lock();
cl([](std::string& s) {
s = "we should still be foobar";
});
cl([](std::string& s) {
std::cout << s;
});
}
This is completely unimplementable. A trivial modification of your source code shows why this won't work.
int main()
{
const_lock<std::vector<int>> v;
v.push_back(5);
v.push_back(7);
if (rand() % 2)
v.set_const_lock(true);
v.push_back(9); // fails compilation
std::cout << v.at(1) << std::endl; // ok
}
You need to completely rethink your approach.
Below is an example illustrating what I would be trying to protect against
class Node
{
public:
Node(int id) : my_id(id) {}
// . . .
int id() {return my_id;}
private:
int my_id;
// . . .
};
class Grid
{
public:
Grid() {}
// . . .
void associate(Node* n) { my_nodes.push_back(n); }
private:
// . . .
std::vector<Node*> my_nodes;
};
Node* find(std::vector<Node>& Nodes, int ID)
{
for(auto i=Nodes.begin(); i!=Nodes.end(); ++i)
{
if (i->id() == ID)
{
return &*i;
}
}
}
main()
{
std::vector<Node> Nodes;
// fill Nodes with data
Grid Array;
Array.associate( find(Nodes,14325) );
Array.associate( find(Nodes,51384) );
Array.associate( find(Nodes,321684) );
// . . .
Nodes.push_back(Node(21616)); // this can invalidate my pointers in Array
}
If I was able to make my Nodes vairable be
const_lock<std::vector<Node>> Nodes;
then call
Nodes.set_const_lock(true);
after populating the data, I wouldn't need to worry about my pointers in Array getting messed up.
I am still relatively new to C++, learning as I go, and I'm confused as to what is the 'best' way to expose the vector to its consumers. I'm not worried about performance.
I have a class that contains a vector of raw data. I have other classes that need to consume and process that vector.
From reading other posts here I'm not sure whether to return a const reference to the vector or expose const iterators as none of the consumers will modify the vector.
Is one way better than the other? Are there other options or other things to consider ?
typedef std::vector<int> RawNumberContainer;
typedef std::vector<int>::const_iterator RawNumberIterator;
class RawData
{
public:
RawData();
void addNumber(int number)
{
rawNumbers.push_back(number);
}
// this?
RawNumberContainer getRawNumbers() { return rawNumbers; }
// or this?
const RawNumberContainer& getRawNumbersConstReference() { return rawNumbers; }
// or this?
RawNumberIterator getRawNumbersBeginning() { return rawNumbers.begin(); }
RawNumberIterator getRawNumbersEnd() { return rawNumbers.begin(); }
private:
RawNumberContainer rawNumbers;
};
class Something;
class RawDataConsumer
{
public:
// ??
Something* processRawData(RawNumberContainer&);
// ??
Something* processRawData(const RawNumberContainer&);
// ??
Something* processRawData(RawNumberIterator begin, RawNumberIterator end);
};
It:
const RawNumberContainer& getRawNumbersConstReference() const { return rawNumbers; }
And it:
Something* processRawData(const RawNumberContainer&);
You can use:
RawNumberContainer getRawNumbers() const { return rawNumbers; }
This way you'll make sure you can't edit the vector (only read-only access) and spare you of another variable being manually declared in your code.
So, I have got the following classes and methods:
Property: Has a single member of type int (named mTag)
TypedProperty: Inherits from the Property class and adds a member called mValue of type T to it.
PropertyList: A class which Maintains a std::set of Property and has an Add and Print method.
CheckSubset: A method which checks if a std::set is included in another set.
I don't know how I should implement the CheckSubset method. Because I do not know how to iterate through a set<Property> and access to the template member (mValue). I also tried to use the includes method, which did not work (even if it worked, I would have no idea how it did!). The same problem exists in the PropertyList::Print method, where I do not know what cast should be used.
Any advice on the implementation of CheckSubset and Print methods would be appreciated!
Updated source code (using pointer)
#include <string>
#include <iostream>
#include <set>
#include <algorithm>
#include <tr1/memory>
using namespace std;
/////////////////// Property Class //////////////////////
class Property
{
public:
Property(){};
Property(const int tag)
: mTag(tag) {}
virtual ~Property() {}
int mTag;
bool operator<(const Property &property) const
{
return mTag < property.mTag;
}
};
/////////////////// TypedProperty Class /////////////////
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const int tag, const T& value)
: Property(tag), mValue(value){}
T mValue;
};
/////////////////////////////////////////////////////////
typedef std::tr1::shared_ptr<Property> PropertyPtr;
/////////////////// PropertyList Class /////////////////
class PropertyList
{
public:
PropertyList(){};
virtual ~PropertyList(){};
template <class T>
void Add(int tag, T value)
{
PropertyPtr ptr(new TypedProperty<T>(tag, value));
mProperties.insert(ptr);
}
void Print()
{
for(set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++)
{
cout << ((PropertyPtr)*itr)->mTag << endl;
// What should I do to print mValue? I do not know its type
// what should *itr be cast to?
}
}
set<PropertyPtr> mProperties;
};
//////////////////// Check Subset ///////////////////////
/*
* Checks if subset is included in superset
*/
bool CheckSubset(set<PropertyPtr> &superset, set<PropertyPtr> &subset)
{
// How can I iterate over superset and subset values while I do not know
// the type of mValue inside each Property?
// I also tried the following method which does not seem to work correctly
return includes(superset.begin(), superset.end(),
subset.begin(), subset.end());
}
int main()
{
PropertyList properties1;
properties1.Add(1, "hello");
properties1.Add(2, 12);
properties1.Add(3, 34);
properties1.Add(4, "bye");
properties1.Print();
PropertyList properties2;
properties2.Add(1, "hello");
properties2.Add(3, 34);
if(CheckSubset(properties1.mProperties, properties2.mProperties)) // should be true
cout << "properties2 is subset!" << endl;
PropertyList properties3;
properties3.Add(1, "hello");
properties3.Add(4, 1234);
if(CheckSubset(properties1.mProperties, properties3.mProperties)) // should be false
cout << "properties3 is subset!" << endl;
}
What you want, cannot be done with the current design.
Your approach fails with std::set<Property>.
std::set<Property> will slice. That means that it will only copy the Property part and forget to copy the additional TypedProperty<T> members.
As a result, inside PropertyList::print(), there is no way to access the mValue.
If you want to store TypedProperty<T>s inside a std::set, you must use some sort of pointer. I.e. either std::set<Property*>, or a smart pointer version.
For solving the problem in Print method of PropertyList, you could write a Print method for TypedProperty class, which prints its tag and value.
But about the problem in accessing mValue which you want to do some operations on, I can't think of a way using normal types and templates to get the mValue without engaging your parent class Property with template type of TypedProperty (which seems undesirable). But you could get the address of mValue and cast it to void* to eliminate the type problem. This way you will face another problem, that you can not point to value of a void* pointer, so you can not work with your pointer in parent level. Therefore, you should write a method (implemented by TypedProperty) that takes a void* pointer and casts it to the type defined in child and perform the desired operation.
For example in the following code, I assumed you want to check equality of a value in a TypedProperty with another one of the same type (IsEqual method).
Now you can implement simply CheckSubset using IsEqual (checking two elements would be like: superItr->IsEqual(subItr->GetValue())).
class Property
{
public:
Property(){};
Property(const int tag)
: mTag(tag) {}
virtual ~Property() {}
virtual void* GetValue() = 0;
virtual bool IsEqual(void* value) = 0;
virtual void Print() = 0;
int mTag;
bool operator<(const Property &property) const
{
return mTag < property.mTag;
}
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const int tag, const T& value)
: Property(tag), mValue(value){}
void* GetValue()
{
return &mValue;
}
bool IsEqual(void* value)
{
return *((T*)value) == mValue;
}
void Print()
{
cout << "Tag: " << mTag << ", Value: " << mValue << endl;
}
T mValue;
};
typedef std::tr1::shared_ptr<Property> PropertyPtr;
class PropertyList
{
public:
PropertyList(){};
virtual ~PropertyList(){};
template <class T>
void Add(int tag, T value)
{
PropertyPtr ptr(new TypedProperty<T>(tag, value));
mProperties.insert(ptr);
}
void Print()
{
cout << "-----------" << endl;
for(set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++)
{
(*itr)->Print();
}
}
set<PropertyPtr> mProperties;
};