I'm new to the bimap functionality of the Boost libraries, and I'm having trouble passing a bimap into another function. My bimap looks like this:
typedef boost::bimap< int, int > bimap_type;
bimap_type bm;
I have an add_values() function that adds a set of values to the bimap:
add_values(int a, int b)
{
bm.insert(bimap_type::value_type(a, b));
}
I then have a function that is meant to set the values of the bimap by getting them from a Singleton Class:
void set_values()
{
MyClass::instance()->get_values(bm);
}
And, in MyClass, get_values() looks like this:
void get_values(bimap_type myBimap)
{
myBimap.add_values(3, 5);
}
However, MyClass does not recognise 'bimap_type'. I try putting the typedef in a separate header file and including that in MyClass, but I get the error message:
'class bimap_type' has no member named 'add_values'
How can I successfully pass the bimap to this Singleton Class in order to fill it with values from the Class? Does anyone know?
Thanks a lot.
Er, boost::bimap itself doesn't have an add_values method and it's hard to tell from these code fragments why you're suddenly expecting one to appear.
Consider renaming your functions: set_values() that calls get_values() that calls add_values() is one confusing call chain...
When you need to modify an object in a function, you have to take it by reference (or a pointer). The idea is that you must work with the same object inside and outside of the function. If you pass by value, function will see a copy, so anything it does with it does not reflect on original object.
// formerly known as add_values()
void initialize(bimap_type& bm, int a, int b)
{
bm.insert(bimap_type::value_type(a, b));
}
And this is how you will call it:
initialize(myBitmap, 3, 5);
Make sure to update your whole call chain to pass by reference where appropriate, because currently your get_values() works with a copy too.
Related
Here is the code:
class SomeType {
public:
SomeType() {}
~SomeType() {}
std::string xxx;
}
bool funtion_ab() {
SomeType(); // This is a right val;
// The right val destructs here when I test the code. I want to make sure that it would always destructs here.
int a = 0, b = 10;
....// other code
return true;
}
Please tell me if you know the truth. Thank you!
What you have is called a temporary object. From §6.7.7,
Temporary objects are created
when a prvalue is converted to an xvalue
or, more specifically,
[Note 3: Temporary objects are materialized:
...
when a prvalue that has type other than cv void appears as a discarded-value expression ([expr.context]).
— end note]
and, on the lifetime, the same section has this to say
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
You can read more about the expression semantics, but in your case "full-expression" is fairly unambiguous.
SomeType();
The "full-expression" containing your constructor call is... the constructor call itself. So the destructor will be called immediately after evaluating the constructor. There are some exceptions to this rule (such as if the temporary object is thrown as an exception or is bound as a reference), but none of those apply here.
As noted in the comments, compilers are free to inline your constructor and destructor calls and then are free to notice that they do nothing and omit them entirely. Optimizers can do fun stuff with your code, provided it doesn't change the semantics. But a strict reading of the standard states that the destructor is called exactly where you suggested.
I'm building a publish-subscribe class (called SystermInterface), which is responsible to receive updates from its instances, and publish them to subscribers.
Adding a subscriber callback function is trivial and has no issues, but removing it yields an error, because std::function<()> is not comparable in C++.
std::vector<std::function<void()> subs;
void subscribe(std::function<void()> f)
{
subs.push_back(f);
}
void unsubscribe(std::function<void()> f)
{
std::remove(subs.begin(), subs.end(), f); // Error
}
I've came down to five solutions to this error:
Registering the function using a weak_ptr, where the subscriber must keep the returned shared_ptr alive.
Solution example at this link.
Instead of registering at a vector, map the callback function by a custom key, unique per callback function.
Solution example at this link
Using vector of function pointers. Example
Make the callback function comparable by utilizing the address.
Use an interface class (parent class) to call a virtual function.
In my design, all intended classes inherits a parent class called
ServiceCore, So instead of registering a callback function, just
register ServiceCore reference in the vector.
Given that the SystemInterface class has a field attribute per instance (ID) (Which is managed by ServiceCore, and supplied to SystemInterface by constructing a ServiceCore child instance).
To my perspective, the first solution is neat and would work, but it requires handling at subscribers, which is something I don't really prefer.
The second solution would make my implementation more complex, where my implementation looks as:
using namespace std;
enum INFO_SUB_IMPORTANCE : uint8_t
{
INFO_SUB_PRIMARY, // Only gets the important updates.
INFO_SUB_COMPLEMENTARY, // Gets more.
INFO_SUB_ALL // Gets all updates
};
using CBF = function<void(string,string)>;
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, vector<CBF>>;
using REQINF_SUBS = map<string, INFO_SUBTREE>; // It's keyed by an iterator, explaining it goes out of the question scope.
using INFSRC_SUBS = map<string, INFO_SUBTREE>;
using WILD_SUBS = INFO_SUBTREE;
REQINF_SUBS infoSubrs;
INFSRC_SUBS sourceSubrs;
WILD_SUBS wildSubrs;
void subscribeInfo(string info, INFO_SUB_IMPORTANCE imp, CBF f) {
infoSubrs[info][imp].push_back(f);
}
void subscribeSource(string source, INFO_SUB_IMPORTANCE imp, CBF f) {
sourceSubrs[source][imp].push_back(f);
}
void subscribeWild(INFO_SUB_IMPORTANCE imp, CBF f) {
wildSubrs[imp].push_back(f);
}
The second solution would require INFO_SUBTREE to be an extended map, but can be keyed by an ID:
using KEY_T = uint32_t; // or string...
using INFO_SUBTREE = map<INFO_SUB_IMPORTANCE, map<KEY_T,CBF>>;
For the third solution, I'm not aware of the limitations given by using function pointers, and the consequences of the fourth solution.
The Fifth solution would eliminate the purpose of dealing with CBFs, but it'll be more complex at subscriber-side, where a subscriber is required to override the virtual function and so receives all updates at one place, in which further requires filteration of the message id and so direct the payload to the intended routines using multiple if/else blocks, which will increase by increasing subscriptions.
What I'm looking for is an advice for the best available option.
Regarding your proposed solutions:
That would work. It can be made easy for the caller: have subscribe() create the shared_ptr and corresponding weak_ptr objects, and let it return the shared_ptr.
Then the caller must not lose the key. In a way this is similar to the above.
This of course is less generic, and then you can no longer have (the equivalent of) captures.
You can't: there is no way to get the address of the function stored inside a std::function. You can do &f inside subscribe() but that will only give you the address of the local variable f, which will go out of scope as soon as you return.
That works, and is in a way similar to 1 and 2, although now the "key" is provided by the caller.
Options 1, 2 and 5 are similar in that there is some other data stored in subs that refers to the actual std::function: either a std::shared_ptr, a key or a pointer to a base class. I'll present option 6 here, which is kind of similar in spirit but avoids storing any extra data:
Store a std::function<void()> directly, and return the index in the vector where it was stored. When removing an item, don't std::remove() it, but just set it to std::nullptr. Next time subscribe() is called, it checks if there is an empty element in the vector and reuses it:
std::vector<std::function<void()> subs;
std::size_t subscribe(std::function<void()> f) {
if (auto it = std::find(subs.begin(), subs.end(), std::nullptr); it != subs.end()) {
*it = f;
return std::distance(subs.begin(), it);
} else {
subs.push_back(f);
return subs.size() - 1;
}
}
void unsubscribe(std::size_t index) {
subs[index] = std::nullptr;
}
The code that actually calls the functions stored in subs must now of course first check against std::nullptrs. The above works because std::nullptr is treated as the "empty" function, and there is an operator==() overload that can check a std::function against std::nullptr, thus making std::find() work.
One drawback of option 6 as shown above is that a std::size_t is a rather generic type. To make it safer, you might wrap it in a class SubscriptionHandle or something like that.
As for the best solution: option 1 is quite heavy-weight. Options 2 and 5 are very reasonable, but 6 is, I think, the most efficient.
ALL,
I have a function with the following signature:
void foo(const std::vector<Bar *> &myvec);
Inside this function I need to loop thru the members of the vector and perform some operations.
So, I tried this:
for( std::vector<Bar *>::const_iterator it = myvec.begin(); it < myvec.end(); ++it )
{
// modify properties of Bar * pointer
(*it)->SetSomeValue( baz );
}
however this code asserts since the iterator is constant.
Now obviously the vector is constant, which means that the function shouldn't be modifying myvec.
What's the best solution here?
Can I use const_cast here to remove constness? It would be kind of hack-ish, but if it works.
But I feel there must be a better solution.
TIA!!
You should use the myvec.cbegin() method instead of myvec.begin(), to ensure that you are not modifying the object the iterator points to.
Of course, for myvec.end(), use myvec.cend() accordingly.
The iterator itself doesn't need to be a const_iterator, in the contrary, you want to modify the objects it gives you - set_...() sounds like a non-const activity.
I have a function that is part of a class handles some input as pair of iterators. The signature of which is:
class Obj {
public:
template <typename InputIterator>
void handle_read(InputIterator first, InputIterator last);
...
};
I would like to bind that to a function:
void Obj::handle_connect() {
connections.start(std::make_shared<connection>(std::move(socket), connections, logger),
std::bind(&server::handle_read<InputIterator>, this, std::placeholders::_1, std::placeholders::_2));
}
However that doesn't work, specifically the error suggests that it can't find InputIterator.
However if I put the exact signature for the bind in:
std::bind(&server::handle_read<std::array<uint8_t, 8192>::iterator>, this, std::placeholders::_1, std::placeholders::_2));
It compiles, but the code is brittle: If I change to a vector then I will need to go around changing the signatures (though failing code will be easy to detect), and if I decide that a different container would be more efficient than an array in a particular use case, then it breaks altogether.
How I do keep the bind generic and not tied to a particular iterator type?
I have the following member variable in a class:
std::vector<std::unique_ptr<Object>> objects_;
I explicitly want the vector to maintain ownership at all times. I've seen suggestions that in order for a member function to access a pointer in the vector and make changes to the object T wrapped in the std::unique_ptr, we must move the pointer to calling code, i.e:
void foo(int i) {
auto object = std::move( vector.at( i ) ); // move object to caller (caller owns)
object->dosomething();
vector.at(i) = std::move(object); // move back into vector (vector owns)
}
Another method was to work with raw pointers:
void foo(int i) {
Object* object = vector.at( i ).get();
object->doSomething();
}
However, I've been working with this:
void foo(int i) {
auto& object = vector.at( i );
object->doSomething();
}
Which is the correct and most robust method for my case? Does this function ever take ownership of the data in the std::unique_ptr? Is there a way to access Object without playing with the std::unique_ptr?
(excuse me if my methods are incorrect, I hope I got the point across)
The first approach will not retain ownership of the object if object->dosomething() throws an exception (i.e. it is not exception safe) since the second std::move() statement will not be executed.
Assuming C++11, both of the other approaches are effectively equivalent, subject to the assumption that the owned pointer is not null. Under the same assumption, the code can be simplified to
void foo(int i)
{
vector.at(i)->doSomething();
}
which will work with all C++ standards (not just C++11 or later).
It is possible to access the object without monkeying with the unique_ptr - simply store the pointer elsewhere and use that. However, that does compromise the purpose of using std::unique_ptr in the first place. And is error-prone - for example, the std::unique_ptr can destroy the object, and leave those other pointers dangling.
If you are really that worried about the potential of your vector losing ownership, consider using a shared_ptr instead.