I have a function which creates an array of Maps:
map<string, int> *pMap
And a function which writes maps to the array:
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
{
m = &(pMap[i]);
memcpy(m, mapToAdd, sizeof(map<string, int>));
}
And a function to get maps from the array
map<string, int>& getMap(int i)
{
return pMap[i];
}
I can write maps to the array without any issue, but every get call results in a seg fault:
int val;
// val defined after this
map<string, int> * pGetMap = &(getMap(val));
Any suggestions on why this is happening?
You cannot use memcpy() to copy objects like maps, or indeed any other kind of C++ container - you need to use assignment, which takes into account the map's underlying structure and se,mantics. And you should be using a vector <map>, as you actually seem to want a copy rather than a pointer.
Never ever use memcpy for copying an object of a map (or whatever class, for that matter) - use assignment or copy constructor instead. memcpy is a C function, which has no idea of the internal structure of a C++ object, so it is almost guaranteed to mess things up.
Also you would better use an std::vector<map<string, int> > instead of an array:
std::vector<map<string, int> > maps;
void addMap(const map<string, int>& mapToAdd, int i)
{
maps[i] = mapToAdd;
}
map<string, int>& getMap(int i)
{
return maps[i];
}
Note: addMap does not return anything in your example code, so I changed its return type to void. Also I pass mapToAdd as const reference rather than by value.
This seems like an unholy mix of C and C++ programming, begin with changing:
memcpy(m, mapToAdd, sizeof(map<string, int>));
to
*m = *mapToAdd;
Also in the function
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
What is the purpose of m? Any modifications to m won't be seen outside of this function.
Related
I was playing through c++ and trying to understand vector and its signature .
In below method printPrimes I need to use pointer with address of why ?
Is vector<int> &primes not enough as from main method printPrimes is already sending address .
void printPrimes(long long l, long long r, vector<int>* &primes) {
// some code
}
vector<int>* sieve() {
vector<int> *prime = new vector<int>();
return prime;
}
int main() {
vector<int> *primes = sieve();
printPrimes(l, r, primes);
return 0;
}
I need to use pointer with address of
Here, & does not mean "address of"; it means the type "reference to".
It's clearer if you write it not like this:
vector<int>* &primes
but like this:
vector<int>*& primes
Though the choice of whitespace is artificial, that better documents that this & is "part of the type".
Have some types:
std::vector<T> = A vector of Ts
std::vector<T>& = A reference to a vector of Ts
std::vector<T>* = A pointer to a vector of Ts
std::vector<T>*& = A reference to a pointer to a vector of Ts
std::vector<T>*** = A pointer to a pointer to a pointer to a vector of Ts
std::vector<T>**& = A reference to a pointer to a pointer to a vector of Ts
…and so forth.
As for why you need a vector<int>*& for printPrimes to do its job, we could not tell you without actually being able to see it. I will say that it seems unlikely it needs a pointer at all, and that if it wants to modify that pointer it's going to cause problems with the new and delete in the calling scope.
In fact, all that dynamic allocation is completely pointless and only complicates things.
The following was likely intended instead:
void printPrimes(long long l, long long r, vector<int>& primes) {
// some code
}
vector<int> sieve() {
vector<int> prime;
return prime;
}
int main() {
vector<int> primes = sieve();
printPrimes(l, r, primes);
}
vector<int>* &primes parameter has to be read this way:
Reference to a pointer of vector of int
and not
Address of a pointer of vector of int (which, you are right, would be useless)
Passing by reference allows to directly manipulate any instance outside of scope (like with pointers, but a safer way since a reference cannot be nullptr, and its existence is auto-managed (no need to delete)).
In c++ & in function parameter used to pass parameter by reference. vector<int>* &primes declares primes to be a reference to a pointer to vector<int>.
If printPrimes means to print only the vector passed to the function then the signature
void printPrimes(long long l, long long r, vector<int> &primes);
can also do the job.
Reference to a pointer is needed when the pointer passed to the function is need to be modified and it's effect is expected to seen in the caller function.
void foo(int*& p){
p = new int[10];
// rest of the code
}
if a function bar is calling foo like
void bar(/* some parameters */){
// ...
int *p;
foo(p);
// rest of the code
}
foo is modifying the pointer itself and this modification will be seen to bar also and memory allocated to p can be accessed from bar.
#include <vector>
int main()
{
typedef const std::vector<const int> set_t;
set_t Low = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
return 0;
}
When compiling the above code I got trillion of errors from STL headers.
What I want to do here is to initialize a vector and ensure that values can not be changed at some point later and also to make sure that no new values can be added.
This vector should be created once with initial values and not changed in any way.
What's wrong here?
This is also a const vector, and it will let your code compile.
typedef const std::vector<int> set_t;
Making the std::vector alone const will expose only the non-modifying interface. Your ints will not change.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why isn't the [] operator const for STL maps?
I've boiled this down to (what I think is) its simplest form:
#include <iostream>
#include <map>
#include <vector>
class NumberHolder
{
public:
NumberHolder( const std::string aKey, const double aNumber );
void printSmallestMappedNumber( const unsigned int theIndex ) const;
private:
std::vector< std::map< std::string, double> > theNamedNumberMapVector;
};
NumberHolder::NumberHolder( const std::string key, const double aNumber )
{
std::map<std::string, double> aTempMap;
aTempMap[key] = aNumber;
theNamedNumberMapVector.push_back(aTempMap);
}
void NumberHolder::printSmallestMappedNumber( const unsigned int theIndex ) const
{
std::map<std::string, double>& aSpecificMap = theNamedNumberMapVector[theIndex];
std::cout << aSpecificMap["min"] << std::endl;
}
int main(int argc, char* argv[])
{
NumberHolder aTaggedNumberHolder("min", 13);
aTaggedNumberHolder.printSmallestMappedNumber( 0 );
return 0;
}
I have a vector full of maps, and each map is full of (string) "tagged" numbers. I'm trying to keep as tight of control over access to the visibility/mutability of the variables involved.
Anyhow, the compiler fails with this error
Binding of reference to type 'std::map' to a value of type 'const std::map, double, std::less >, std::allocator, double> > >' drops qualifiers
My first (underbaked) attempt was making the map const..., as I'm not modifying the map, only retrieving a value from it:
const std::map<std::string, double>& aSpecificMap = theNamedNumberMapVector[theIndex];
Which then presents me with this admittedly shorter, but actually a bit more confusering error:
No viable overloaded operator[] for type 'const std::map<std::string, double>'
On the following line instead:
std::cout << aSpecificMap["min"] << std::endl;
However, perhaps because I've been trying to untangle this for a bit, my solution seems to be awfully, awfully crufty:
std::map<std::string, double>& aSpecificMap = const_cast<std::map<std::string, double>&>(theNamedNumberMapVector[theIndex]);
const_casting away the [const derp] qualifier works around my problem, but I would really like to have a clear understanding of exactly what's going on. I'm guessing that the compiler is disgruntled about my access to the map (in my second attempt, above) and believes that I will use & abuse my access to the map's contents. I'd really like / need to be able to explain stuff like this to other people, as well as trying not to abuse the language and ultimately end up on The Daily WTF, because, you know, shame and stuff.
If you look at the declaration for map's operator[], you will see that it is not const qualified, which is why it cannot be called on a const std::map<std::string, double>. The reason it is not const is because if the key does not exist in the map, it creates it. You should instead use find or at to get the element.
map<>::operator[] creates elements in the map if they don't already exist, which is why it's not allowed on a const object. You should use find().
(Some of the linked-at-right questions already answer this: e.g. Why isn't the [] operator const for STL maps? - I'll vote to close this as a duplicate)
I'm trying to sort a concurrent_vector type, where hits_object is:
struct hits_object{
unsigned long int hash;
int position;
};
Here is the code I'm using:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
Now I have filled up a concurrent_vector<hits_object*> called hits.
But I want to sort this concurrent_vector on position property!!!
Here is an example of what's inside a typical hits object:
0 1106579628979812621
4237 1978650773053442200
512 3993899825106178560
4749 739461489314544830
1024 1629056397321528633
5261 593672691728388007
1536 5320457688954994196
5773 9017584181485751685
2048 4321435111178287982
6285 7119721556722067586
2560 7464213275487369093
6797 5363778283295017380
3072 255404511111217936
7309 5944699400741478979
3584 1069999863423687408
7821 3050974832468442286
4096 5230358938835592022
8333 5235649807131532071
I want to sort this based on the first column ("position" of type int). The second column is "hash" of type unsigned long int.
Now I've tried to do the following:
std::sort(hits.begin(),hits.end(),compareByPosition);
where compareByPosition is defined as:
int compareByPosition(const void *elem1,const void *elem2 )
{
return ((hits_object*)elem1)->position > ((hits_object*)elem2)->position? 1 : -1;
}
but I keep getting segmentation faults when I put in the line std::sort(hits.begin(),hits.end(),compareByPosition);
Please help!
Your compare function needs to return a boolean 0 or 1, not an integer 1 or -1, and it should have a strongly-typed signature:
bool compareByPosition(const hits_object *elem1, const hits_object *elem2 )
{
return elem1->position < elem2->position;
}
The error you were seeing are due to std::sort interpreting everything non-zero returned from the comp function as true, meaning that the left-hand side is less than the right-hand side.
NOTE : This answer has been heavily edited as the result of conversations with sbi and Mike Seymour.
int (*)(void*, void*) is the comparator for C qsort() function. In C++ std::sort() the prototype to the comparator is:
bool cmp(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
std::sort(hits.begin(), hits.end(), &cmp);
On the other hand, you can use std::pair struct, which by default compares its first fields:
typedef std::pair<int position, unsigned long int hash> hits_object;
// ...
std::sort(hits.begin(), hits.end());
Without knowing what concurrent_vector is, I can't be sure what's causing the segmentation fault. Assuming it's similar to std::vector, you need to populate it with hits.push_back(obj) rather than hits[i] = j; you cannot use [] to access elements beyond the end of a vector, or to access an empty vector at all.
The comparison function should be equivalent to a < b, returning a boolean value; it's not a C-style comparison function returning negative, positive, or zero. Also, since sort is a template, there's no need for C-style void * arguments; everything is strongly typed:
bool compareByPosition(hits_object const * elem1, hits_object const * elem2) {
return elem1->position < elem2->position;
}
Also, you usually don't want to use new (and certainly never malloc) to create objects to store in a vector; the simplest and safest container would be vector<hits_object> (and a comparator that takes references, rather than pointers, as arguments). If you really must store pointers (because the objects are expensive to copy and not movable, or because you need polymorphism - neither of which apply to your example), either use smart pointers such as std::unique_ptr, or make sure you delete them once you're done with them.
The third argument you pass to std::sort() must have a signature similar to, and the semantics of, operator<():
bool is_smaller_position(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
When you store pointers in a vector, you cannot overload operator<(), because smaller-than is fixed for all built-in types.
On a sidenote: Do not use malloc() in C++, use new instead. Also, I wonder why you are not using objects, rather than pointers. Finally, if concurrent_vector is anything like std::vector, you need to explicitly make it expand to accommodate new objects. This is what your code would then look like:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object obj;
obj.position=i;
obj.hash=_prevHash[tid];
hits.push_back(obj);
}
This doesn't look right:
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
here you already are sorting the array based on 'i' because you set position to i as well as it becomes the index of hits!
also why using malloc, you should use new(/delete) instead. You could then create a simple constructor for the structure to initialize the hits_object
e.g.
struct hits_object
{
int position;
unsigned int hash;
hits_object( int p, unsigned int h ) : position(p), hash(h) {;}
};
then later write instead
hits_object* obj = new hits_object( i, _prevHash[tid] );
or even
hits.push_back( new hits_object( i, _prevHash[tid] ) );
Finally, your compare function should use the same data type as vector for its arguments
bool cmp( hits_object* p1, hits_object* p2 )
{
return p1->position < p2->position;
}
You can add a Lambda instead of a function to std::sort.
struct test
{
int x;
};
std::vector<test> tests;
std::sort(tests.begin(), tests.end(),
[](const test* a, const test* b)
{
return a->x < b->x;
});
Suppose I have
vector<vector<int> > a;
which is indexed as
a[i][j] = stuff;
where i is "outer" and j is "inner"...
Then creating a reference to the "outer" vector is easy:
vector<int>& b = a[x];
Is there a nice way to create a reference to the inner?
vector<int>& b = a[<don't know>][x];
Thanks.
Unfortunately, no, there's no direct way of creating a reference like that because the compiler is treating this like
a.operator[] (/* ... don't know ... */).operator[] (x);
This only makes sense if the first call to operator [] actually hands back a vector.
However, what you can do is fake this behavior by introducing a new class that specifically handles the behavior. The idea is to have this class store the second index and provide an operator[] function that, given the first index, looks up the real value in the vector. Here's one example:
class IndexReverser { // Or, your favorite name
public:
IndexReverser(vector< vector<int> >& v, size_t index);
int& operator[] (size_t firstIndex);
private:
vector< vector<int> >& realVector;
const size_t secondIndex;
};
IndexReverser::IndexReverser(vector< vector<int> >&v,
size_t index) : realVector(v), secondIndex(index) {
// Handled in initialization list
}
int& IndexReverser::operator[] (size_t firstIndex) {
return realVector[firstIndex][secondIndex];
}
You could then write, for example, this:
IndexReverser ir(a, j);
ir[i] = 137;
You might need to provide a twin class to handle const vectors, and probably would want to parameterize the entire structure on the type of the elements being stored. I'm not sure if this is what you're looking for, but it least shows that in principle you can get the behavior you want.
This line:
vector<int>& b = a[x];
is not a reference to the outer vector but rather one of the inner vectors. Also note that there are possible many inner vectors.
Here's how to get a reference to the outer vector (although in general it would be pointless):
vector<vector<int> > &outer = a;
Getting a reference to one of the inner vectors looks something like this:
vector<int> &inner = a[x];