C++ priority_queue size() issue - c++

I tried to get the size of an empty priority_queue. Something strange happened. Could anybody explain why this happened? Thanks a lot.
#include <iostream>
#include <queue>
using namespace std;
int main()
{
priority_queue<int, vector<int>, less<int> > asc_queue;
cout << asc_queue.size() << " " << asc_queue.size() - 1 << endl;
}
Output:
0 18446744073709551615

std::priority_queue::size() returns the size of the container as a std::size_t (technically the size_type of the underlying container of the priority queue) which is essentially an unsigned int - therefore trying to minus 1 from an empty container size gives you the unsigned decimal representation of 0xffffffffffffffffL which is why you get the large value you see.

Related

use an empty {} to initialize a vector is different?

I see some people tend to initialize a vector with an empty {}, and I wonder whether it is different from directly initialize with the default constructor?
for example:
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec;
vector<int> vec2 {};
cout << sizeof(vec) << " " << sizeof(vec2) << endl; // 24 24
cout << vec.size() << " " << vec2.size() << endl; // 0 0
}
and I check its assembly code, and it shows that initializing a vector with an empty {} generate more code(https://godbolt.org/z/2BAWU_).
Assembly code screen shot here
I am quite new to C++ language, and I would be grateful if someone could help me out.
Using braces is value initialization. Not using them is default initialization. As somebody alluded to in the comments, they should generate the exact same code when optimizations are turned on for vector. There's a notable difference with built-in types like pointers and int; there default initialization does nothing, while value initialization sets them to nullptr and zero, respectively.

Node size for unordered_map buckets

I have a program where I want to store kmers (substrings of size k) and the number of times they appear. For this particular application, I'm reading in a file with these values and if the number of times they appear is > 255, it is ok to round down to 255. I thought that if I store the key-value pairs as (string, unsigned char) that might save space compared to storing the key-value pairs as (string, int), but this did not seem to be the case when I checked the max resident size by running /usr/bin/time.
To confirm, I also tried running the following test program where I alternated the type of the value in the unordered_map:
#include <iostream>
#include <unordered_map>
#include <utility>
#include <string>
#include <fstream>
int main() {
std::unordered_map<std::string, unsigned char> kmap;
std::ifstream infile("kmers_from_reads");
std::string kmer;
int abun;
while(infile >> kmer >> abun) {
unsigned char abundance = (abun > 255) ? 255 : abun;
kmap[kmer] = abundance;
}
std::cout << sizeof(*kmap.begin(0)) << std::endl;
}
This did not seem to impact the size of the nodes in the bucket (on my machine it returned 40 for both unsigned char and int values).
I was wondering how the size of the nodes in each bucket is determined.
My understanding of unordered maps is that the c++ standard more or less requires separate chaining and each node in a bucket must have at least one pointer so that the elements are iterable and can be erased (http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html). However, I don't understand how the amount of space to store a value is determined, and it seems like it must also be flexible to accommodate larger values. I also tried looking at the gcc libstc++ unordered_map header (https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/unordered_map.h) but had a hard time understanding what was going on.
Compile and execute this code:
#include <iostream>
#include <unordered_map>
#include <utility>
#include <string>
#include <fstream>
class foo
{
std::string kmer;
unsigned char abun;
};
class bar
{
std::string kmer;
int abun;
};
int main() {
std::cout << sizeof(foo) << " " << sizeof(bar) << std::endl;
}
I get, and you probably will too, 40 40. This is because of alignment requirements. If, for example, std::string contains at least one pointer (which it almost certainly does), it has to be aligned on at least a 4-byte boundary.
Imagine if sizeof(foo) was 39 and you had code that did foo foos[2]. If the pointer in foos[0].kmer was properly aligned, the pointer in foos[1].kmer wouldn't be. That would be a disaster.

how can I make strptime work on a vector of struct tm in c++?

I'm working in a c++ application that read a csv file and stores the content in a matrix of doubles and in a vector of struct tm. I have something similar to this:
#include <iostream>
#include <time.h>
#include <vector>
using namespace std;
int main(){
vector<struct tm> tmTM;
strptime("20020202", "%Y%m%d", &tmTM[0]);
cout << tmTM[0].tm_year << endl;
cout << tmTM[0].tm_mday << endl;
cout << tmTM[0].tm_mon << endl;
return 0;
}
Unfortunly this code generate a error Segmentation fault (core dumped)
I'm a begginer in c++ so I don't know what is wrong with the code.
Thanks a lot!
The default constructor for a vector generates an empty vector. That means that any access to an element, even element [0], will result in undefined behavior.
The usual way to handle this is to work with a temporary variable, then use push_back to place the temporary into the vector.
struct tm temp;
strptime("20020202", "%Y%m%d", &temp);
tmTM.push_back(temp);

Making maps using the boost::variant library. How to store and display things as the proper type?

I'm trying to create a map using the boost::variant library, but I can't seem to get any of the data held within the map to print properly.
Code:
#include <string>
#include <iostream>
#include "boost_1_55_0/boost/any.hpp"
#include "boost_1_55_0/boost/variant.hpp"
#include <map>
#include <list>
#include <complex>
#include <vector>
using namespace std;
int main()
{
std::map <string, boost::variant <int, double, bool, string> > myMap;
myMap.insert(pair<string, int>("PAGE_SIZE",2048));
myMap.insert(pair<string, boost::variant <int, double,bool, string> > ("PAGE_SIZE2", "hello, this is a string" )); //setup an enum to specify the second value maybe?
cout << "data page 1: " << myMap["PAGE)SIZE1"] << "\ntype page 1: " << myMap["PAGE_SIZE"].which() << endl;
cout << "data: " << myMap["PAGE_SIZE2"] << "\ntype: "<< myMap["PAGE_SIZE2"].which()<< endl;
return 0;
}
Ignore all the extra includes, I've been using this file to play around with lots of different ideas. When I compile with g++, I get the following:
data page 1: 0
type page 1: 0
data page 2: 1
type page 2: 2
I get that the first variable is being stored as an int, and is therefore of type 0, but why is it displaying a value of 0?
Same thing with the second output, except that I don't understand why it's being stored as a bool, is the value a 1 (true)?
All help is appreciated.
Thanks!
The second is being stored as a bool because it's a more basic conversion than to std::string (the compiler prefers const char* -> bool to const char* -> std::string). As the pointer is non-null it assigns the boolean value true. You can specifically construct a std::string here to work around the default conversion.
As for why the data output isn't functioning the only thing I can suspect is that possibly BOOST_NO_IOSTREAM is set, causing it to not have the appropriate operator<<.

<Functional>: plus<long>() on integers gives unexpected result

I don’t understand why I do not get the same results in these two cases:
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<int> v;
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0, plus<long long>());
cout << r << endl;
return 0;
}
Anyone any ideas?
EDIT: as correctly pointed out below, this is due to the sign bit in int I wasn't counting on. 0x7FFFFFFF would obviously be better for testing. Also, I erroneously expected that the return type of plus() would be the same as for accumulate(), which is not the case: it is based on the third argument.
There are two problems here:
The number 0xFFFFFFFF won't fit in an int (assuming 32-bit ints), so the value stored in the vector is actually -1 on most implementations. Using vector<unsigned int> or vector<long long> should fix this.
The type returned by accumulate is the type deduced from the third parameter. Since you passed in 0, this will be int. You should pass in 0LL instead so that it returns long long.
This program with both fixes will return the correct result:
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<long long> v; //or vector<unsigned int>
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0LL, plus<long long>());
cout << r << endl;
return 0;
}
Because your vector contains type int and 0xFFFFFFFF doesn't fit into it. Try to change it to long long.
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<long long> v;
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0LL, plus<long long>());
cout << r << endl;
return 0;
}
EDIT:
Also, as pointed by interjay, third parameter should have type long long since accumulate uses it to deduce resulting type.
Your vector stores type int which is probably a 32 bit type. From 4.7/3 we learn:
If the destination type is signed, the value is unchanged if it can be
represented in the destination type (and bit-field width); otherwise,
the value is implementation-defined.
In other words, your value 0xFFFFFFFF can't be represented in the destination signed type so the results are implementation defined. In this case, it most likely took the obvious twos-comp result and stored a -1 in the vector. Then when you do the accumulate, it adds -1 (because it doesn't change the stored -1) and 2, resulting in the 1 being printed.
Most likely you wanted to store long long in the vector (since you're summing values larger than a 32 bit can hold), and as noted in other answers you would also need to pass 0LL to accumulate to force it to infer the correct return type.