Can converting structure elements to const-reference save some overhead? - c++

Scenario,
I have a trace file having thousands of 'Entries'(I call them 'tick').
Each 'Entry' contains several lines of information.
There are two types of information(location data and multicast data) so each line is either about 'location' or 'multicast'.
Goal:
My goal is to store them into my data structure efficiently:
Implementation:
for storing information of each entry, I have :
//////////////////
struct multicast_data{
//... integers, vectors of integers, string etc.
}
std::list<multicast_data> multicasts;
///////////////////////
struct AgentLocation{
//... integers, operator overload etc.
};
std::set<AgentLocation> agentsLocation;
////////////////////////
Next, I want to store the entries in a queue, So I first bundle them in another structure like this:
struct tickDataBundle{
const std::list<multicast_data> & multicasts;
const std::set<AgentLocation> & agentsLocation;
tickDataBundle(const std::list<multicast_data> &multicasts,
const std::set<AgentLocation> &agentsLocation):
multicasts(multicasts),
agentsLocation(agentsLocation){}
};
then I put them into a queue:
MessageQueue<tickDataBundle> m_processed_data;
Questions:
My confusion is, the containers(list and set) in tickDataBundle are created and populated in the scope of some method, and naturally these containers are destroyed when the scope ends(no heap). So even returning the reference to these containers will create dangling reference. So I figured if,before the scope ends, I add the const-reference of these containers to tickDataBundle object, then push this object to the MessageQueue , I would have benefitted from the C++'s optimization to save the full containers from being destroyed and reduce some copying overhead. was this a correct and valid assumption?
why cant't I save a const-reference of tickDataBundle in the above queue?
(MessageQueue<const tickDataBundle&> m_processed_data; generates error)
thank you
UPDATE: this part is JUST FOR YOUR REFERENCE
I am copying
the structure of my MessageQueue and
the error I will get if I declare MessageQueue<const tickDataBundle&> m_processed_data;
template<class T>
class MessageQueue {
std::queue<T> messageList;
boost::shared_mutex mutex;
public:
MessageQueue();
virtual ~MessageQueue();
bool ReadMessage();
void post(T message);
bool pop(T&);
void clear();
int size();
};
error:
In file included from /usr/include/c++/4.8/deque:64:0,
from /usr/include/c++/4.8/queue:60,
from ./ns3/drop-tail-queue.h:22,
from ./ns3/network-module.h:24,
from ../src/simmobility/examples/simmobility-RR-baseline.cc:2:
/usr/include/c++/4.8/bits/stl_deque.h: In instantiation of ‘class std::_Deque_base<const sim_mob::RoadRunnerBaseLine::tickDataBundle&, std::allocator<const sim_mob::RoadRunnerBaseLine::tickDataBundle&> >’:
/usr/include/c++/4.8/bits/stl_deque.h:730:11: required from ‘class std::deque<const sim_mob::RoadRunnerBaseLine::tickDataBundle&, std::allocator<const sim_mob::RoadRunnerBaseLine::tickDataBundle&> >’
/usr/include/c++/4.8/bits/stl_queue.h:96:46: required from ‘class std::queue<const sim_mob::RoadRunnerBaseLine::tickDataBundle&, std::deque<const sim_mob::RoadRunnerBaseLine::tickDataBundle&, std::allocator<const sim_mob::RoadRunnerBaseLine::tickDataBundle&> > >’
./ns3/smb_message_queue.h:18:16: required from ‘class sim_mob::MessageQueue<const sim_mob::RoadRunnerBaseLine::tickDataBundle&>’
./ns3/smb_roadrunner_baseline.h:87:47: required from here
/usr/include/c++/4.8/bits/stl_deque.h:448:60: error: forming pointer to reference type ‘const sim_mob::RoadRunnerBaseLine::tickDataBundle&’
typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator;
^
/usr/include/c++/4.8/bits/stl_deque.h:449:60: error: forming pointer to reference type ‘const sim_mob::RoadRunnerBaseLine::tickDataBundle&’
typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
^
/usr/include/c++/4.8/bits/stl_deque.h:488:61: error: forming pointer to reference type ‘const sim_mob::RoadRunnerBaseLine::tickDataBundle&’
typedef typename _Alloc::template rebind<_Tp*>::other _Map_alloc_type;
AND THE ERROR CONTINUES...

1. I figured if I make const-reference if the elements in the tickDataBundle, it will reduce some copying overhead. was this a correct and valid assumption?
The answer is yes. All copy of tickDataBundle objects only own the const reference of multicasts and agentsLocation, not coping real data in them.
*2. why cant't I save a const-reference of tickDataBundle in the above queue? (MessageQueue m_processed_data; generates error)*
The const reference must be assigned at the object construct time point. You can use const pointer as const reference, like this:
MessageQueue<const tickDataBundle*> m_processed_data;

Related

Can I pass a const object to db.persist in ODB?

I'm trying out ODB ORM and I have to stick to an interface, so I need to take a const object and persist it. I'm not sure if the ODB API allows to persist a const object, because some part seems prepared for that, but it doesn't work.
I am receiving this error from gcc here:
void OdbReportRW::write_object(const MyObject &my_object)
{
odb::core::transaction t{db->begin()};
db->persist(my_object);
t.commit();
}
this is the error, which I think it says that my_object should not be const:
In file included from /usr/local/include/odb/database.hxx:632:0,
from odb_report.hpp:21,
from src/vcf/odb_report.cpp:18:
/usr/local/include/odb/database.txx: In instantiation of ‘typename odb::object_traits<T>::id_type odb::database::persist_(T&) [with T = const MyObject; odb::database_id DB = (odb::database_id)5u; typename odb::object_traits<T>::id_type = long unsigned int]’:
/usr/local/include/odb/database.ixx:167:45: required from ‘typename odb::object_traits<T>::id_type odb::database::persist(const T&) [with T = MyObject; typename odb::object_traits<T>::id_type = long unsigned int]’
src/vcf/odb_report.cpp:134:26: required from here
/usr/local/include/odb/database.txx:38:39: error: no matching function for call to ‘odb::object_traits_impl<MyObject, (odb::database_id)5u>::persist(odb::database&, const MyObject&)’
object_traits::persist (*this, obj);
^
/usr/local/include/odb/database.txx:38:39: note: candidate is:
In file included from src/vcf/odb_report.cpp:27:0:
my-object-error-odb.hxx:247:5: note: static void odb::access::object_traits_impl<MyObject, (odb::database_id)1u>::persist(odb::database&, odb::access::object_traits<MyObject>::object_type&)
persist (database&, object_type&);
^
my-object-odb.hxx:247:5: note: no known conversion for argument 2 from ‘const MyObject’ to ‘odb::access::object_traits<MyObject>::object_type& {aka MyObject&}’
Same error with clang, a bit more descriptive:
In file included from src/vcf/odb_report.cpp:18:
In file included from inc/vcf/odb_report.hpp:21:
In file included from /usr/local/include/odb/database.hxx:632:
/usr/local/include/odb/database.txx:38:36: error: binding of reference to type 'object_type' (aka 'MyObject') to a value of type 'const MyObject' drops qualifiers
object_traits::persist (*this, obj);
^~~
/usr/local/include/odb/database.ixx:167:12: note: in instantiation of function template specialization 'odb::database::persist_<const MyObject, 5>' requested here
return persist_<const T, id_common> (obj);
^
src/vcf/odb_report.cpp:134:13: note: in instantiation of function template specialization 'odb::database::persist<MyObject>' requested here
db->persist(my_object);
^
inc/vcf/error-odb.hxx:247:37: note: passing argument to parameter here
persist (database&, object_type&);
^
However, I can see in the database interface (from odb) that both types of persist are provided: reference and const reference (and other with pointers):
// in odb/database.hxx
template <typename T>
typename object_traits<T>::id_type
persist (T& object);
template <typename T>
typename object_traits<T>::id_type
persist (const T& object);
I saw that a similar error is raised (for find, not persist) when there's no default constructor in the class to persist (MyObject here), but it is there, so it's not the problem. I already checked that the default constructor only generates an extra method find in the generated code.
It worked removing the const specifier in my write_object method, but as I said, I have to stick to an interface.
Any ideas to persist a const object?
reading more thoroughly the documentation I found this (http://www.codesynthesis.com/products/odb/doc/manual.xhtml#3.8):
The first persist() function expects a constant reference to an instance being persisted. The second function expects a constant object pointer. Both of these functions can only be used on objects with application-assigned object ids (Section 14.4.2, "auto").
indeed, I was using the auto specifier for database-handled ids:
// class MyObject
#pragma db id auto
unsigned long id_;
So it seems that I can not use at the same time the auto id and the const reference persist.

Compiler says object is const, I can't see how

I'm having trouble with this code:
NonCommutativePolynomial<SR> differential_at_wrt_variable
(std::map<VarId,SR> valuation, VarId variable) {
NonCommutativePolynomial<SR> result;
for(auto &monomial : monomials_) {
result += monomial.first.differential_at_wrt_variable(valuation, variable)
* monomial.second;
}
return result;
}
monomials_ has the type std::map<NonCommutativeMonomial<SR>,std::uint_fast16_t>.
In the line result += ... I'm getting this compiler error:
error: passing ‘const NonCommutativeMonomial’ as ‘this’
argument of ‘NonCommutativeMonomial
NonCommutativeMonomial::differential_at_wrt_variable(std::map&, VarId&) [with SR = LossySemiring]’ discards qualifiers
[-fpermissive]
Now I realize that this means that I am calling a method (function?) on a constant object where the method does not guarantee that it won't modify the object. What I don't understand is how monomial.first can be constant when I haven't declared it to be thus anywhere. Any ideas what I might be doing wrong?
EDIT:
See the answers below why monomial.first is constant. I need a non-constant copy of it, the class NonCommutativeMonomial<SR>has this copy constructor:
NonCommutativeMonomial(const NonCommutativeMonomial &m) = default;
However, when I call that using
NonCommutativeMonomial * mono = new NonCommutativeMonomial<SR>(monomial.first);
and work with mono afterwards, I still get the same error.
In std::map keys are constant objects and you must never change them.
EDIT:
I'd suggest the following change:
NonCommutativePolynomial<SR> result;
for(auto &monomial : monomials_) {
NonCommutativePolynomial<SR> tmp(monomial.first);
result += tmp.differential_at_wrt_variable(valuation, variable)
* monomial.second;
}
it seems that member function differential_at_wrt_variable has no qualifier const while monomial.first is a const object.
Value type is defined for std::map as
typedef pair<const Key, T> value_type;
that is Key has qualifier const.
The value_type of a std::map<KeyType, MappedType> is declared as a std::pair<const KeyType, MappedType>.
An iterator for a std::map (which is what your for loop is using) is over the map's value_type.
In your case this results in monomial.first having the type const NonCommutativeMonomial<SR> which, as you recognise, cannot be used with a non-const member function.
The reason for the key in the value type being const is to prevent the map keys themselves being modified during the iteration.

shared_ptr initialization

A member is defined as
std::shared_ptr<std::array<std::string, 6> > exit_to;
which points to additional data shared among others.
When try to initiate the pointer "exit_to". The correct way is
node_knot.exit_to = std::make_shared<std::array<std::string, 6> >();
But it's in another file and I'd like to keep the pointer type consistent, something like this:
node_knot.exit_to = std::make_shared<decltype(*node_knot.exit_to)>();
But won't compile:
/usr/include/c++/4.6/bits/shared_ptr_base.h:798:54: error: '__p'
declared as a pointer to a reference of type
'std::array<std::basic_string<char>, 6> &'
__shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, _Tp* __p)
^ /usr/include/c++/4.6/bits/shared_ptr.h:93:31: note: in instantiation
of template class
'std::__shared_ptr<std::array<std::basic_string<char>, 6> &, 1>'
requested here
class shared_ptr : public __shared_ptr<_Tp>
^ ../node_booker.h:757:20: note: in
instantiation of template class
'std::shared_ptr<std::array<std::basic_string<char>, 6> &>' requested
here
n.exit_to = std::make_shared<decltype(*n.exit_to)>();
I'm under Ubuntu 12.10, clang++ 3.2, with --std=c++11
You need to remove the reference from the type you are passing to make_shared.
The following should work:
node_knot.exit_to = std::make_shared<std::remove_reference<decltype(*node_knot.exit_to)>::type>();
The problem is that the type of *exit_to is a reference, and you can't have a shared_ptr to a reference.
You could remove the reference, but instead of finding the type returned by operator* and then stripping the reference off it, it's probably easier to just ask the shared_ptr what type it contains:
node_knot.exit_to = std::make_shared<decltype(node_knot.exit_to)::element_type>();
The nested element_type is the type stored by the shared_ptr.
Another option would be to add a typedef to the class and use it consistently wherever you need it:
typedef std::array<std::string, 6> string_array;
std::shared_ptr<string_array> exit_to;
// ...
node_knot.exit_to = std::make_shared<Node::string_array>();
This is a lot more readable than using decltype

trouble creating a custom sort in C++ for a vector of pointers

I am trying to create a custom sort for a vector of class pointers by using a sort predicate:
struct sort_by_airtime
{
inline bool operator() (const Network *n1, const Network *n2)
{
return (n1->airtime() < n2->airtime());
}
};
For each network, we sort by a float returned by airtime().
Now, I try to use this as follows:
std::vector<Network *> Simulator::sort_networks(std::vector<Network *> netlist, bool sort_airtime) {
std::vector<Network *> new_netlist = netlist;
if(sort_airtime) {
sort(new_netlist.begin(), new_netlist.end(), sort_by_airtime());
}
}
However, I get a lot of errors like this:
In file included from Simulator.cpp:7:
Simulator.h: In member function ‘bool Simulator::sort_by_airtime::operator()(const Network*, const Network*)’:
Simulator.h:48: error: passing ‘const Network’ as ‘this’ argument of ‘virtual float Network::airtime()’ discards qualifiers
Simulator.h:48: error: passing ‘const Network’ as ‘this’ argument of ‘virtual float Network::airtime()’ discards qualifiers
Am I not specifying the argument passed to the predicate properly? airtime() is implemented by classes that inherit the Network class.
The compiler is warning you that Network::airtime() is ignoring the const qualifiers on n1 and n2.
The solution would be to create a "const-correct" version of Network::airtime() (assuming it actually doesn't modify anything).
See this answer for an example.
Your member function should be declared as const member function as:
virtual float Network::airtime() const
^^^^^ //this makes the function const
because the pointers which you're using in operator() are pointing to const objects of type Network.
Network::airtime() is not const, and so can't be called via the const Network* you have in sort_by_airtime.
If possible, the best solution is to make airtime() const; otherwise change the sort_by_airtime arguments to Network*.

pointer assignment

I have the following template structure:
template <typename scalar_type>
struct postc_params{
scalar_type delta;
unsigned int time_horizon;
matrix_math::matrix<scalar_type> dynamics;
boost::shared_ptr<continuous_set> invariant_set_ptr;
boost::shared_ptr<continuous_set> input_set_ptr;
boost::shared_ptr<continuous_set> initial_set_ptr;
};
Now, I have a templated class with a private member of the above structure type
template <typename scalar_type>
class A{
....
private:
....
postc_params<scalar_type> my_postc;
};
Inside a member function definition of class A, I have the following line of code:
my_postc.initial_set_ptr = my_postc.initial_set_ptr->transform(some_obj);
transform function returns a pointer of type
boost::shared_ptr<continuous_set>
With this code, I have the following error:
passing 'const boost::shared_ptr' as 'this' argument of 'boost::shared_ptr< >& boost::shared_ptr< >::operator=
(const boost::shared_ptr&) [with Y = const continuous::continuous_set, T = continuous::continuous_set]' discards qualifiers
Can anyone help me out with the cause?
Is the member function in A const?
If I am reading your code right, you are trying to change a member of a class from a const member function which is not allowed. Either remove the const from the member function or make the member mutable.
So,
mutable postc_params<scalar_type> my_postc;
However, I would take care with this method. Maybe reevaluate why the method that is changing my_postc is const. Either it should not be const or it should not be changing my_postc.
you are trying to assign to a const pointer as per the error message: "passing 'const boost::shared_ptr' as 'this' argument"
the member function you mention is surely const hence the error
you should rather reconsider your design than throw mutable here and there in your code.