In the past I have used both templates and dynamic binding in C++, however recently I attempted to use them together and found that it was impossible to compile.
What I am trying to do is something like this:
std::map<MyClass, unsigned int> mymap;
Where MyClass happens to be a class utilizing dynamic memory binding. After a few hours of searching I am given the impression that this causes implications which I still can't resolve, so I was hoping for some guidance on the issue and how it can be resolved.
My final goal is to be able to do something like this:
std::vector<MyClass> MyClassPool;
//fill the vector with MyClass objects...
for(usigned int i=0 ; i<MyClassPool.size() ; i++)
{
mymap[ MyClassPool[i] ] = i;
}
I have tried using pointers in various ways but it's not working and I fail to see what can be done.
I get the following errors with the above:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h: In member function `bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Instance]':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_map.h:338: instantiated from `_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = Instance, _Tp = float, _Compare = std::less<Instance>, _Alloc = std::allocator<std::pair<const Instance, float> >]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_function.h:227: error: no match for 'operator<' in '__x < __y'
That compile error means you have no operator < defined for Instance. map needs to be able to sort keys and needs this function. If you'd rather not define operator <, you need to provide a comparison function as a third template parameter for map, i.e. std::map<Instance, float, compare_instances>.
... Come to think of it, you're sure you want Instance as the key and float as the data, and not the other way around? I.e. you're searching in the map for an Instance to get a float in return?
You don't provide operator< for MyClass. It is required by std::map. You have two options: provide a comparator as the third template argument to map OR implement the operator in MyClass.
This has nothing to do with "dynamic binding" (which is not what is meant here anyway). Your class needs to have an order to be put into a map. It needs operator<.
Related
I am writing a program that passes around a struct type that I don't want to be modified. This struct has two const members, and looks as follows:
struct system_s {
std::string name;
std::string pkg;
char *const start_cmd[10];
char *const end_cmd[10];
bool ros;
bool equals(const system_s &cmp);
};
The struct is being stored in a map with the following format. It is a class member:
std::map<std::string, system_s> sys_map;
There is another temporary map. Think of sys_map as a cache if you prefer. But really you don't have to worry about how it is being used for the sake of this question. sys_map is being called to add a system to the temporary map as follows. It is in a class method:
add_system(sys_map[msg->system]); (*)
This function has the following definition. It is a class method:
int add_system(const system_s &sys);
When (*) is called, I get the following error:
system.h: In instantiation of ?std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::basic_string<char>; _Tp = system_s; _Compare = std::less<std::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::basic_string<char>, system_s> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = system_s; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::basic_string<char>]?:
/tc_manager_node.cpp:74:41: required from here
/system.h:26:8: error: uninitialized member ?system_s::start_cmd? with ?const? type ?char* const [10]? [-fpermissive]
struct system_s {
^
system.h:26:8: error: uninitialized member ?system_s::end_cmd? with ?const? type ?char* const [10]? [-fpermissive]
In file included from /usr/include/c++/4.8/map:61:0,
from /opt/ros/indigo/include/ros/console.h:42,
from /opt/ros/indigo/include/ros/ros.h:40,
from
/tc_manager_node.cpp:2:
/usr/include/c++/4.8/bits/stl_map.h:469:59: note: synthesized method ?system_s::system_s()? first required here
__i = insert(__i, value_type(__k, mapped_type()));
Why is this member of type system_s 'uninitialized'? It presumably stored already initialized in sys_map. Does it have something to do with passing the system_s as a reference in int add_system(const system_s &sys)?
The operator[] of map (which you invoke with sys_map[msg->system]) has the possibility of creating a new entry if the map entry is not found. The new entry is default-constructed, but your class is not default-constructible.
To fix this, don't use [] on the map. Instead use find to find the entry you are looking for.
As #Greg Kikola said, const members must be initialized. Check here on how to do that with initializer lists (Not to be confused with std::initializer_list): http://en.cppreference.com/w/cpp/language/initializer_list
The position of the const with pointers can sometimes be confusing. X * const p indicates:
“p is a const pointer to an X that is non-const”: you can’t change the pointer p itself, but you can change the X object via p. [source]
This means that the address a system_s is created with can never be changed. Which is bad since you're not constructor-initializing start_cmd or end_cmd this means that none of the 10 pointers can be assigned a valid address. They start with an uninitialized addresses and can never be assigned anything else.
EDIT:
This post is tagged: c++03. There is no straight forward way to initialize arrays in C++03. You can look at this question for some workarounds: Initializing a member array in constructor initializer If you have the ability to go with c++11 you can use List Initialization.
This is my first time trying to incorporate STL into my code and I just have a few simple syntax questions I can't seem to figure out.
So I have created a vector of pointers:
std::vector<event_tracking*> track[10];
and within a loop in the main program I want to call
track[nfd] = new event_tracking(pfd[nfd].fd, initial_requests);
but this line gives the error
error: no match for 'operator=' in '((Pds::MyXtcMonitorServer*)this)->Pds::MyXtcMonitorServer::track[nfd] = (((event_tracking*)operator new(12u)), (<anonymous>->event_tracking::event_tracking(((Pds::MyXtcMonitorServer*)this)->Pds::MyXtcMonitorServer::pfd[nfd].pollfd::fd, ((Pds::MyXtcMonitorServer*)this)->Pds::MyXtcMonitorServer::initial_requests), <anonymous>))'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/vector.tcc:133: note: candidates are: std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::operator=(const std::vector<_Tp, _Alloc>&) [with _Tp = event_tracking*, _Alloc = std::allocator<event_tracking*>]
and later on I want to call a function of my class like:
char* p = track[j]->receive_datagram();
But I get the error
error: base operand of '->' has non-pointer type 'std::vector<event_tracking*, std::allocator<event_tracking*> >'
and then I try to call delete like:
delete track[j];
and get the error:
error: type 'class std::vector<event_tracking*, std::allocator<event_tracking*> >' argument given to 'delete', expected pointer
I am really confused because I thought the way to call a function in a class when pointers are involved was by using the -> and I don't understand why that doesn't work here. I also don't understand why the [ ] aren't being used correctly to reference a specific element in the vector. If someone could please explain where my syntax errors are here and why they are arising that would be great! thank you
std::vector<event_tracking*> track[10];
This doesn't create a vector of 10 pointers. It creates an array of 10 empty vectors of pointers. To create a single vector of 10 pointers, use parentheses instead of square brackets.
std::vector<event_tracking*> track(10);
I have a class I've written, meant to represent vectors (in the linear algebra sense). I just started writing it so it isn't finished, but i've pasted it and some test code here
I'm not really sure what's going on. I was going to write an overloaded operator<< for testing in a second, so I went ahead and put it in my main function (so I could use compiler errors to make sure I'd written it properly).
What does this warning mean? why it is looking at the address of v? I tried removing the parentheses from v, and I end up with this, a bunch of horrible template errors:
`
In function 'typename boost::range_const_iterator<C>::type boost::range_detail::boost_range_begin(const C&) [with C = vect<float, 3u>]':
/usr/local/include/boost/range/begin.hpp:164: instantiated from 'typename boost::range_const_iterator<C>::type boost::begin(const T&) [with T = vect<float, 3u>]'
prelude/more_stdlib_ostreaming.hpp:64: instantiated from 'void more_stdlib_ostreaming_detail::print_range(std::basic_ostream<_CharT, _Traits>&, const Range&) [with C = char, Tr = std::char_traits<char>, Range = vect<float, 3u>]'
prelude/more_stdlib_ostreaming.hpp:76: instantiated from 'typename more_stdlib_ostreaming_detail::snd<typename R::iterator, std::basic_ostream<_CharT, _Traits>&>::type operator<<(std::basic_ostream<_CharT, _Traits>&, const R&) [with C = char, Tr = std::char_traits<char>, R = vect3f]'
t.cpp:42: instantiated from here
Line 45: error: 'const class vect<float, 3u>' has no member named 'begin'`
I can sort of see whats going on here, tho. It looks like it is somehow using boost's range for and trying to iterate over my container, and it is failing because I haven't defined begin() and end(). The same thing happens if I instantiate v using v(some_float) rather than without the parens.
So, two questions:
Why is v() behaving differently than v? I thought that declaring a object without parens always calls the default ctor anyway, and explicitly calling the default ctor made no difference?
What is codepad's compiler (gcc 4.1.2) doing here? Does it have a template that automatically tries to generate an appropriate operator<
Also, feel free to tell me anything else I'm doing stupid/wrong/bad style here (besides rolling my own matrix math library for fun, which I know is unnecessary. I'm doing it as an exercise)
First of all, vect3f v(); declares a function (named v), taking no parameters and returning vect3f. And the operator<< that is being called is called for this function pointer (which is implicitly converted to bool, because there's no overload for function pointers).
vect3f v; is the correct way of creating default-constructed object.
And no, compiler won't try to generate ostream& operator<<(ostream& /* ... */) for you. There are however many overloads for all fundamental types and even some other types (such as std::string).
You can check all basic overloads here.
why is it so useful to make a function const if you only can read variables but not write(class variable)?
If you pass something else a const pointer or const reference to an instance of your class then it can only call the class's const methods (if any).
Obviously, if you never bother with const-correctness with your types then you can ignore this.
I suppose it may also help the compiler optimize things in certain situations, although I am doubtful and, even if it did help, allowing that small improvement (if any) to dictate how you wrote your code would be a case of premature optimization in most situations.
So that you do not "accidentally" modify one of the class variables. It is just a safety measure.
(If you use the const keyword after a function that does modify any data member of the class - either directly or through another function call - you will get a compilation error).
One reason is that const is a virus. That means that if part of the code is const-correct, then the rest of the code won't interoperate with that part.
If you ignore const-correctness, chances of your classes working hand-in-hand with other libraries (beginning with the standard library) are slim.
For example:
#include <vector>
#include <algorithm>
struct X
{
int n;
bool operator< (X b)
{
return n < b.n;
}
};
int main()
{
std::vector<X> vec;
std::sort(vec.begin(), vec.end());
}
With codepad.org
In function 'const _Tp& std::__median(const _Tp&, const _Tp&, const _Tp&) [with _Tp = X]':
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2642: instantiated from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >, _Size = int]'
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:2713: instantiated from 'void std::sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<X*, __gnu_norm::vector<X, std::allocator<X> > >, __gnu_debug_def::vector<X, std::allocator<X> > >]'
t.cpp:17: instantiated from here
Line 90: error: no match for 'operator<' in '__a < __b'
A stdlib compatible comparison operator must make a promise that arguments are not modified. If objects actually were to change while they are compared, an attempt to sort them would be rather futile.
Another example: you won't be able to pass arguments by const reference which is the conventional way of passing large objects. Instead you'd have to pass arguments by modifiable references. Now you won't be able to pass temporaries of any kind to your functions.
If you have a const object, it only allows const member functions to operate on it.
The more of the contract between caller and callee you can express in code instead of documentation, the more help the compiler can give you with complying with that contract (from both ends). const-ness of the implicit this pointer is an important part of that as is const-ness of all other parameter referents. (of course top-level constness of pass-by-value parameters is not part of the contract)
The benefit is that you can get the compiler to enforce where state can be modified. For example if you make a class with private data and all its methods, except, say, the constructor, are const, then you have an immutable data type. The benefit of this is not one of performance, but one of semantics.
Today I created a map, where the value type has no default constructor. I was surprised that I could not use operator[] to insert the elements to this map, but I had to use the insert method.
So, what exactly are requirements for the key and value types for std::map?
Here is short example :
#include <map>
struct A
{
A(int){}
};
int main()
{
std::map< int, A > m;
A a1(2);
A a2(3);
A a3(4);
m[5] = a1;
m[3] = a2;
m[2] = a3;
}
I am compiling like this :
[vladimir#sandbox tmp]$ g++ b5.cpp -Wall -Wextra -ansi -pedantic
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/stl_map.h: In member function ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = A, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, A> >]’:
b5.cpp:14: instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/stl_map.h:419: error: no matching function for call to ‘A::A()’
b5.cpp:5: note: candidates are: A::A(int)
b5.cpp:4: note: A::A(const A&)
operator[] does indeed require default-constructibility because the semantics of this method mandate that if the key doesn’t yet exist, an appropriate entry is created. Thus:
map<TKey, TValue> mymap;
TKey foo = …;
TValue& x = mymap[foo];
will create and store a new object TValue() if foo doesn’t exist in the map, and return a reference to it.
This site make a great STL reference: http://www.sgi.com/tech/stl/
Basically, it says that map takes has mandatory 2 type arguments, Key and Data. Data needs to be Assignable, as Daniel said. Key, however, is stated to need to be a type that can be used with the type Compare, i.e. Compare designates a function object whose parameters are of type Key. In this case, the default Compare function object is std::less<T>, which is a Strict Weak Ordering that compares objects of type T using the operator<. Hence, if you do not change the Compare type, i.e. use the default, std::less<T> will be used with type Key, and thus operator< will be used with type Key, and thus Key needs to be comparable with operator<.
Hope that helps! I know it's a bit gratuitous and I don't mean to be condescending, but I just want to make sure it's absolutely clear how to go about reasoning about this.