Are boost multi_index extracted keys cached? - c++

I am using boost::multi_index with a data type I'd like to index based on its size. However, the size() member function of this data type is expensive to execute. Does multi_index cache the values it gets from its key extractors?
For example, if I created a multi_index container with an ordered index with a member function key (element.size()), and inserted an element whose size put it somewhere in the middle of the container, would the container re-invoke the size() member function on all the elements it visits while traversing its internal data structure before finding the right insertion point?

Well, the documentation for member function indexers says they call the referenced member function: http://www.boost.org/doc/libs/1_46_0/libs/multi_index/doc/reference/key_extraction.html#key_extractors
But when in doubt, profile:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
namespace bmi = boost::multi_index;
int g_calls = 0;
struct A
{
explicit A(int sz) : m_size(sz) { }
int size() const { ++g_calls; return m_size; }
private:
int m_size;
};
typedef boost::multi_index_container<
A*,
bmi::indexed_by<
bmi::ordered_non_unique<
BOOST_MULTI_INDEX_CONST_MEM_FUN(A,int,A::size)
>
>
> container_t;
int main()
{
container_t cont;
int n = 100;
vector<int> o(2*n+1);
for( int i = 0; i != 2*n+1; ++i )
o[i] = i;
random_shuffle(o.begin(), o.end());
for( int i = 0; i != n; ++i )
cont.insert(new A(o[i]));
cout << "Calls to A::size(): "<< g_calls << endl;
for( int i = n+1; i <= 2*n; ++i )
cont.insert(new A(o[i]));
cout << "Calls to A::size(): "<< g_calls << endl;
cont.insert(new A(o[n]));
cout << "Calls to A::size(): "<< g_calls << endl;
for( int i = 0; i != o.size(); ++i )
cont.find(o[i]);
cout << "Calls after calling find " << o.size() << " times: "<< g_calls << endl;
return 0;
}
Gives the following output (using Boost 1.46):
Calls to A::size(): 629
Calls to A::size(): 1465
Calls to A::size(): 1474
Calls after calling find 201 times: 3262
So, it appears the answer is no, it doesn't cache values.

Related

Declaring sqrt(var) as a compile time constant in c++

I have a c++ program where I need to pass the square root of a number in a for loop.
#include<random>
#include<iostream>
#include<algorithm>
#include<string>
#include<math.h>
#include <stdlib.h>
#include <windows.h>
#include <ctype.h>
#include <omp.h>
using namespace std;
int main()
{
vector<int>inputDataBits(49); // vector of randomly generated input data bits
#ifdef printDebug
std::cout << "the input data bits are" << endl;
std::cout << "-------------------------" << endl << endl;
int var =49;
const int r=(int)sqrt(var);
float input2d[r][r];
for (int i = 0; i < r; i++)
{
for (int j = 0; j < r; j++)
{
input2d[i][j] = inputDataBits[(j %r) + (i *r)];
std::cout << input2d[i][j] << "\t";
}
std::cout << endl << endl;
}
std::cout << endl << endl;
#endif
return 0;
}
I get an error 'expression must have a constant value'. Is there a way to do this in c++?
This is the purpose of the constexpr keyword (make the value known at compile time).
constexpr int var=49;
constexpr int r=(int)sqrt(var);
Unfortunately, in the documentation sqrt() is not declared as a constexpr function.
Only gcc seems to consider it as constexpr but it is not portable.
The size of an array needs to be known at compile-time.
Instead you can use a std::vector, which has a dynamic size.
std::vector<std::vector<float>> input2d(std::vector<float>(r), r);

vector with reinterpret_cast

The following code inserts only one value to the vector col.
The code is extracted from DBMS code base (for importing files), specifically, it is from 1
The code uses void* to be able to read any field type (int, float, and so on).
#include <iostream>
#include <vector>
using namespace std;
void add(std::vector<void*> &col){
reinterpret_cast<std::vector<int>&>(col).push_back( 1);
reinterpret_cast<std::vector<int>&>(col).push_back( 2);
reinterpret_cast<std::vector<int>&>(col).push_back( 13);
}
int main() {
std::vector<void*> col;
add(col);
cout << col.size() << endl;
for(int i=0;i<col.size();i++)
cout <<reinterpret_cast<std::vector<int>&> (col)[i] <<endl;
return 0;
}
I am not sure how this code work?
Your code is exhibiting undefined behavior.
std::vector<void*> and std::vector<int> are two completely separate and unrelated types, you can't safely cast between them the way you are, especially since there is no guarantee that void* and int are the same byte size.
Cast the values you are pushing, don't cast the vector itself, eg:
#include <iostream>
#include <vector>
#include <cstdint>
using namespace std;
void add(std::vector<void*> &col) {
col.push_back(reinterpret_cast<void*>(static_cast<intptr_t>(1)));
col.push_back(reinterpret_cast<void*>(static_cast<intptr_t>(2)));
col.push_back(reinterpret_cast<void*>(static_cast<intptr_t>(13)));
}
int main() {
std::vector<void*> col;
add(col);
cout << col.size() << endl;
for(int i=0;i<col.size();i++)
cout << reinterpret_cast<intptr_t>(col[i]) << endl;
return 0;
}
Of course, you really should be using the proper container type to begin with:
#include <iostream>
#include <vector>
using namespace std;
void add(std::vector<int> &col) {
col.push_back(1);
col.push_back(2);
col.push_back(13);
}
int main() {
std::vector<int> col;
add(col);
cout << col.size() << endl;
for(int i=0;i<col.size();i++)
cout << col[i] << endl;
return 0;
}

STL vector containing vector causing segfault

The following code causes a segfault when I try to issue my push_back call. What am I doing wrong?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
std::string * foo = new std::string("hello world");
cout << *foo << endl;
std::vector<std::vector<std::string *> > my_vecs;
my_vecs[0].push_back(foo); // segfaults
cout << "trying to print my_vecs size of " << my_vecs.size() << " but we never reach that point due to segfault " << endl;
return 0;
}
I'm pretty sure I'm violating one of the contracts for using vector, as the problem is surely not with the STL implementation.
When you create my_vecs it has 0 elements, hence my_vecs[0] does not exists and gives segfault. You have to first reserve at least one element of my_vecs and then you can insert in the vector my_vecs[0] your pointer:
std::vector<std::vector<std::string *> > my_vecs(1);
my_vecs[0].push_back(&foo);
The outer vector must first be explicitly grown, before one can push to its elements.
This may be a little surprising since STL map's automatically insert their keys. But, it's certainly the way it is.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
const int DESIRED_VECTOR_SIZE = 1;
std::string * foo = new std::string("hello world");
cout << *foo << endl;
std::vector<std::vector<std::string *> > my_vecs;
for (int i = 0; i < DESIRED_VECTOR_SIZE; ++i) {
std::vector<std::string *> tmp;
my_vecs.push_back(tmp); // will invoke copy constructor, which seems unfortunate but meh
}
my_vecs[0].push_back(foo); // segfaults
cout << "now able to print my_vecs size of " << my_vecs.size() << endl;
return 0;
}

Class template implementation with multiple vectors

I'm creating a program that reads in a data file into a vector and then shows the minimum and maximum information for the vector. I also have to use a class template for finding the minimum and maximum. I'm wondering if there is a way I can reference ANY vector without having to specifically label the two vectors I want to use. In my code below, I have to state vector v1 to get my template to do the minimum and maximum. Is it possible to make this template for any vector?
//Nicholas Stafford
//COP2535.0M1
//Read in text file into multiple vectors and display maximum and minimum integers/strings.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
//Template code area
template <class T>
T min(vector<T> v1)
{
T lowest = v1[0];
for (int k = 1; k < 10; k++)
{
if (v1[k] < lowest)
lowest = v1[k];
}
return lowest;
}
template <class T>
T max(vector<T> v1)
{
T highest = v1[0];
for (int k = 1; k < 10; k++)
{
if (v1[k] > highest)
highest = v1[k];
}
return highest;
}
int main() {
//Number of items in the file
const int size = 10;
//Vector and file stream declaration
ifstream inFile;
string j; //String for words in data file
vector<int> v1(size); //Vector for integers
vector<string> v2(size); //Vector for strings
//Open data file
inFile.open("minmax.txt");
//Loop to place values into vector
if (inFile)
{
for (int i = 0; i < size; i++)
{
inFile >> v1[i];
v1.push_back(v1[i]); //Add element to vector
}
cout << "The minimum number in the vector is " << min(v1) << endl;
cout << "The maximum number in the vector is " << max(v1) << endl;
}
else
{
cout << "The file could not be opened." << endl;
}
}
You're having a simple misunderstanding. Just because the function parameter to your min and max is v1 doesn't mean the only thing you can call it with is something called v1. Actually, it will be a local copy of the vector passed in, locally named v1.
#include <vector>
#include <iostream>
template<typename T>
size_t sizeit(std::vector<T> v) // try changing to v1, v2 and vx
{
return v.size(); // change to match
}
int main() {
std::vector<int> v1 { 1, 2, 3, 4, 5 };
std::vector<float> v2 { 1., 2., 3. };
std::cout << "v1 size = " << sizeit(v1) << "\n";
std::cout << "v2 size = " << sizeit(v2) << "\n";
}
Live demo: http://ideone.com/cK13bR

a C++ hash map that preserves the order of insertion [duplicate]

This question already has answers here:
A std::map that keep track of the order of insertion?
(15 answers)
Closed 10 years ago.
I have the following code:
#include <iostream>
#include "boost/unordered_map.hpp"
using namespace std;
using namespace boost;
int main()
{
typedef unordered_map<int, int> Map;
typedef Map::const_iterator It;
Map m;
m[11] = 0;
m[0] = 1;
m[21] = 2;
for (It it (m.begin()); it!=m.end(); ++it)
cout << it->first << " " << it->second << endl;
return 0;
}
However, I am looking for something that preserves the order so that later I can iterate over the elements in the same order in which they were inserted. On my computer the above code does not preserve the order, and prints the following:
0 1
11 0
21 2
I thought maybe I could use a boost::multi_index_container
typedef multi_index_container<
int,
indexed_by<
hashed_unique<identity<int> >,
sequenced<>
>
> Map;
Can somebody show me how to implement my original code using this container (or any other appropriate container) so that the iterator follows the order of insertion?
#include <iostream>
#include "boost/unordered_map.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
using namespace std;
using namespace boost;
using namespace boost::multi_index;
struct key_seq{};
struct key{};
struct Data_t
{
int key_;
int data_;
Data_t (int key_v, int data_v) : key_(key_v), data_(data_v) {}
};
int main()
{
typedef multi_index_container<
Data_t,
indexed_by<
hashed_unique<tag<key>, BOOST_MULTI_INDEX_MEMBER(Data_t,int,key_)>,
sequenced<tag<key_seq> >
>
> Map;
typedef Map::const_iterator It;
typedef index<Map,key>::type Map_hashed_by_key_index_t;
typedef index<Map,key>::type::const_iterator Map_hashed_by_key_iterator_t;
typedef index<Map,key_seq>::type Map_sequenced_by_key_index_t;
typedef index<Map,key_seq>::type::const_iterator Map_sequenced_by_key_iterator_t;
Map m;
m.insert(Data_t(11,0));
m.insert(Data_t(0,1));
m.insert(Data_t(21,1));
{
cout << "Hashed values\n";
Map_hashed_by_key_iterator_t i = get<key>(m).begin();
Map_hashed_by_key_iterator_t end = get<key>(m).end();
for (;i != end; ++i) {
cout << (*i).key_ << " " << (*i).data_ << endl;
}
}
{
cout << "Sequenced values\n";
Map_sequenced_by_key_iterator_t i = get<key_seq>(m).begin();
Map_sequenced_by_key_iterator_t end = get<key_seq>(m).end();
for (;i != end; ++i) {
cout << (*i).key_ << " " << (*i).data_ << endl;
}
}
return 0;
}
You can try creating an ordered map using the combination of map and the vector.
Vector can hold the pair of key and
value.
Vector iterator can be used as
iterator to traverse ordered map.
map can be used access the elements
faster.