Being quite green with C++, I ran into behavior I don't quite understand, and haven't been able to find an explanation even with intense googling, so I was hoping someone could explain what exactly is wrong here.
// test.h
#include <unordered_map>
typedef std::unordered_map<int, int> test_type;
class test
{
public:
static const test_type tmap;
};
// test.cpp
#include "test.h"
const test_type test::tmap = {
{ 1, 1 }
};
// main.cpp
#include "test.h"
int main()
{
// Attempt 1: access key via operator[]
std::cout << test::tmap[1];
// Attempt 2: access key via at()
std::cout << test::tmap.at(1);
return 0;
}
If I have Attempt 1 in my code, Visual Studio's compiler insists I'm using a binary [ operator that hasn't been defined, but that doesn't really make sense to me because as far as I know there is no binary [ operator, (braces are always unary, right?).
So, why doesn't Attempt 1 work?
The problem is std::unordered_map::operator[] is not const, because it inserts the specified key to the map if it doesn't already exist. Since it is not const you cannot use it with a const object. std::unordered_map::at does have a const overload so it compiles. You either need to make test non-const or just use the at() function.
Related
I have some code like these (from cppcon), when inserting a non-const pair into a unordered_map, the performance is very different to inserting with a const one.
#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <vector>
using namespace std;
struct StopWatch {
StopWatch() : clk{std::chrono::system_clock::now()} {}
~StopWatch() {
auto now = std::chrono::system_clock::now();
auto diff = now - clk;
cout << chrono::duration_cast<chrono::microseconds>(diff).count() << "ms"
<< endl;
}
decltype(std::chrono::system_clock::now()) clk;
};
void Benchmark_Slow(int iters) {
std::unordered_map<string, int> m;
std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
void Benchmark_Fast(int iters) {
std::unordered_map<string, int> m;
const std::pair<const string, int> p = {};
while (iters--)
m.insert(p);
}
int main(void) {
{
StopWatch sw;
Benchmark_Fast(1000000);
}
{
StopWatch sw;
Benchmark_Slow(1000000);
}
return 0;
}
A online demo: Compiler Explorer
128247ms
392454ms
It seems that the const qualifier let the compiler to choose the unordered_map::insert(const value_type&) overload instead of the unordered_map::insert( P&& value ).
cppreference: unordered_map::insert
But I think that a forwarding templated universal reference insert(P&& value) would be the same as an insert with const lvalue reference, an identical copy operation.
But the emplace one(with non-const pair) runs much slower than insert one(with const pair).
Am I missing something here ? Or if this is something has a keyword to be searched on the google, I didn't find something answers that. Thank you in advance.
I think I do found a possible explanation.
from emplace it describe that if insertion fails, the constructed element would be destroyed immediately.
I follow the assembly code compiled with libstd++ of unordered_map::emplace (which accept templated argument and do std::forward) and unordered_map::insert link provided by #Jarod42, I the emplace one always allocate a new hash_node before it check if the key already in the map, because it's templated and it didn't know the argument type (maybe it only know it's is_convertible_to), so it do the construction before examine the key. The one in libc++ seems recognize the type is a const reference thus do the same as the insert one, copy construct occurs only if the key is not exsist.
When I modified the code with different key to be inserted, the difference gone away. quick C++ benchmark
I don't know did I miss something else. I' m sorry for this trivial problem was posted.
If I have the following code that makes use of execution policies, do I need to synchronize all accesses to Foo::value even when I'm just reading the variable?
#include <algorithm>
#include <execution>
#include <vector>
struct Foo { int value; int getValue() const { return value; } };
int main() {
std::vector<Foo> foos;
//fill foos here...
std::sort(std::execution::par, foos.begin(), foos.end(), [](const Foo & left, const Foo & right)
{
return left.getValue() > right.getValue();
});
return 0;
}
My concern is that std::sort() will move (or copy) elements asynchronously which is effectively equivalent to asynchronously writing to Foo::value and, therefore, all read and write operations on that variable need to be synchronized. Is this correct or does the sort function itself take care of this for me?
What if I were to use std::execution::par_unseq?
If you follow the rules, i.e. you don't modify anything or rely on the identity of the objects being sorted inside your callback, then you're safe.
The parallel algorithm is responsible for synchronizing access to the objects it modifies.
See [algorithms.parallel.exec]/2:
If an object is modified by an element access function, the algorithm will perform no other unsynchronized accesses to that object. The modifying element access functions are those which are specified as modifying the object. [ Note: For example, swap(), ++, --, #=, and assignments modify the object. For the assignment and #= operators, only the left argument is modified. — end note ]
In case of std::execution::par_unseq, there's the additional requirement on the user-provided callback that it isn't allowed to call vectorization-unsafe functions, so you can't even lock anything in there.
This is OK. After all, you have told std::sort what you want of it and you would expect it to behave sensibly as a result, given that it is presented with all the relevant information up front. There's not a lot of point to the execution policy parameter at all, otherwise.
Where there might be an issue (although not in your code, as written) is if the comparison function has side effects. Suppose we innocently wrote this:
int numCompares;
std::sort(std::execution::par, foos.begin(), foos.end(), [](const Foo & left, const Foo & right)
{
++numCompares;
return left.getValue() > right.getValue();
});
Now we have introduced a race condition, since two threads of execution might be passing through that code at the same time and access to numCompares is not synchronised (or, as I would put it, serialised).
But, in my slightly contrived example, we don't need to be so naive, because we can simply say:
std::atomic_int numCompares;
and then the problem goes away (and this particular example would also work with what appears to me to be the spectacularly useless std::execution::par_unseq, because std_atomic_int is lockless on any sensible platform, thank you Rusty).
So, in summary, don't be too concerned about what std::sort does (although I would certainly knock up a quick test program and hammer it a bit to see if it does actually work as I am claiming). Instead, be concerned about what you do.
More here.
Edit And while Rusty was digging that up, I did in fact write that quick test program (had to fix your lambda) and, sure enough, it works fine. I can't find an online compiler that supports execution (MSVC seems to think it is experimental) so I can't offer you a live demo, but when run on the latest version of MSVC, this code:
#define _SILENCE_PARALLEL_ALGORITHMS_EXPERIMENTAL_WARNING
#include <algorithm>
#include <execution>
#include <vector>
#include <cstdlib>
#include <iostream>
constexpr int num_foos = 100000;
struct Foo
{
Foo (int value) : value (value) { }
int value;
int getValue() const { return value; }
};
int main()
{
std::vector<Foo> foos;
foos.reserve (num_foos);
// fill foos
for (int i = 0; i < num_foos; ++i)
foos.emplace_back (rand ());
std::sort (std::execution::par, foos.begin(), foos.end(), [](const Foo & left, const Foo & right)
{
return left.getValue() < right.getValue();
});
int last_foo = 0;
for (auto foo : foos)
{
if (foo.getValue () < last_foo)
{
std::cout << "NOT sorted\n";
break;
}
last_foo = foo.getValue ();
}
return 0;
}
Generates the following output every time I run it:
<nothing>
QED.
I'm a newbie to C++ and having an issue regarding std:map with function pointers.
I have created a map which has a string as the key and stored a function pointer as the value. I faced a complication when I tried to use insert() function to add a function pointer. However, it worked when I used [] operator. If you can, please explain this difference.
Here is a sample code I wrote.
OperatorFactory.h
#ifndef OPERATORFACTORY_H
#define OPERATORFACTORY_H
#include <string>
#include <map>
using namespace std;
class OperatorFactory
{
public:
static bool AddOperator(string sOperator, void* (*fSolvingFunction)(void*));
static bool RemoveOperator(string sOperator);
static void RemoveAllOperators();
private:
static map<string , void* (*) (void*)> map_OperatorMap;
};
// Static member re-declaration
map<string, void* (*) (void*)> OperatorFactory::map_OperatorMap;
#endif // OPERATORFACTORY_H
OperatorFactory.cpp
#include "OperatorFactory.h"
void OperatorFactory::RemoveAllOperators()
{
map_OperatorMap.clear();
}
bool OperatorFactory::RemoveOperator(string sOperator)
{
return map_OperatorMap.erase(sOperator) != 0;
}
bool OperatorFactory::AddOperator(string sOperator, void* (*fSolvingFunction)(void*))
{
// This line works well.
map_OperatorMap[sOperator] = fSolvingFunction;
// But this line doesn't.
// map_OperatorMap.insert(sOperator, fSolvingFunction); // Error
return true;
}
The Error says :
error: no matching function for call to 'std::map<std::basic_string<char>, void* (*)(void*)>::insert(std::string&, void* (*&)(void*))'
Even though I got this working (compiled) with the [] operator, I would like to know why I got an error when using insert().
Thank you.
You insert elements into std::map using a std::pair of the key and value:
map.insert(std::make_pair(key,value));
Alternatively you can emplace values in c++11:
map.emplace(key,value);
The [] operator returns a reference to the value for the key passed in:
value_type &
And automatically constructs an element for that key if it doesn't already exist. Make sure you understand what the difference in behavior is between insert() and the [] operator before using them (the latter will replace existing values for a key for example).
See http://en.cppreference.com/w/cpp/container/map for more information.
Consider the following class member:
std::vector<sim_mob::Lane *> IncomingLanes_;
the above container shall store the pointer to some if my Lane objects. I don't want the subroutins using this variable as argument, to be able to modify Lane objects.
At the same time, I don't know where to put 'const' keyword that does not stop me from populating the container.
could you please help me with this?
thank you and regards
vahid
Edit:
Based on the answers i got so far(Many Thanks to them all) Suppose this sample:
#include <vector>
#include<iostream>
using namespace std;
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_)
{
a=a_;
}
void printLane()
{
std::cout << a << std::endl;
}
};
class B
{
public:
vector< Lane const *> IncomingLanes;
void addLane(Lane *l)
{
IncomingLanes.push_back(l);
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(&l1);
b.addLane(&l2);
b.IncomingLanes.at(1)->printLane();
b.IncomingLanes.at(1)->setA(12);
return 1;
}
What I meant was:
b.IncomingLanes.at(1)->printLane()
should work on IncomingLanes with no problem AND
b.IncomingLanes.at(1)->setA(12)
should not be allowed.(In th above example none of the two mentioned methods work!)
Beside solving the problem, I am loking for good programming practice also. So if you think there is a solution to the above problem but in a bad way, plase let us all know.
Thaks agian
A detour first: Use a smart pointer such shared_ptr and not raw pointers within your container. This would make your life a lot easy down the line.
Typically, what you are looking for is called design-const i.e. functions which do not modify their arguments. This, you achieve, by passing arguments via const-reference. Also, if it is a member function make the function const (i.e. this becomes const within the scope of this function and thus you cannot use this to write to the members).
Without knowing more about your class it would be difficult to advise you to use a container of const-references to lanes. That would make inserting lane objects difficult -- a one-time affair, possible only via initializer lists in the ctor(s).
A few must reads:
The whole of FAQ 18
Sutter on const-correctness
Edit: code sample:
#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_) // do you need this?
{
a=a_;
}
void printLane() const // design-const
{
std::cout << a << std::endl;
}
};
class B
{
// be consistent with namespace qualification
std::vector< Lane const * > IncomingLanes; // don't expose impl. details
public:
void addLane(Lane const& l) // who's responsible for freeing `l'?
{
IncomingLanes.push_back(&l); // would change
}
void printLane(size_t index) const
{
#ifdef _DEBUG
IncomingLanes.at( index )->printLane();
#else
IncomingLanes[ index ]->printLane();
#endif
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
//b.IncomingLanes.at(1)->printLane(); // this is bad
//b.IncomingLanes.at(1)->setA(12); // this is bad
b.printLane(1);
return 1;
}
Also, as Matthieu M. suggested:
shared ownership is more complicated because it becomes difficult to
tell who really owns the object and when it will be released (and
that's on top of the performance overhead). So unique_ptr should be
the default choice, and shared_ptr a last resort.
Note that unique_ptrs may require you to move them using std::move. I am updating the example to use pointer to const Lane (a simpler interface to get started with).
You can do it this way:
std::vector<const sim_mob::Lane *> IncomingLanes_;
Or this way:
std::vector<sim_mob::Lane const *> IncomingLanes_;
In C/C++, const typename * and typename const * are identical in meaning.
Updated to address updated question:
If really all you need to do is
b.IncomingLanes.at(1)->printLane()
then you just have to declare printLane like this:
void printLane() const // Tell compiler that printLane doesn't change this
{
std::cout << a << std::endl;
}
I suspect that you want the object to be able to modify the elements (i.e., you don't want the elements to truly be const). Instead, you want nonmember functions to only get read-only access to the std::vector (i.e., you want to prohibit changes from outside the object).
As such, I wouldn't put const anywhere on IncomingLanes_. Instead, I would expose IncomingLanes_ as a pair of std::vector<sim_mob::Lane *>::const_iterators (through methods called something like GetIncomingLanesBegin() and GetIncomingLanesEnd()).
you may declare it like:
std::vector<const sim_mob::Lane *> IncomingLanes_;
you will be able to add, or remove item from array, but you want be able to change item see bellow
IncomingLanes_.push_back(someLine); // Ok
IncomingLanes_[0] = someLine; //error
IncomingLanes_[0]->some_meber = someting; //error
IncomingLanes_.erase(IncomingLanes_.end()); //OK
IncomingLanes_[0]->nonConstMethod(); //error
If you don't want other routines to modify IncomingLanes, but you do want to be able to modify it yourself, just use const in the function declarations that you call.
Or if you don't have control over the functions, when they're external, don't give them access to IncomingLanes directly. Make IncomingLanes private and provide a const getter for it.
I don't think what you want is possible without making the pointers stored in the vector const as well.
const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.
At best, the second version does what you want but you will have this construct throughout your code where ever you do want to modify the data:
const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();
Have you considered a different class hierarchy where sim_mob::Lane's public interface is const and sim_mob::Really_Lane contains the non-const interfaces. Then users of the vector cannot be sure a "Lane" object is "real" without using dynamic_cast?
Before we get to const goodness, you should first use encapsulation.
Do not expose the vector to the external world, and it will become much easier.
A weak (*) encapsulation here is sufficient:
class B {
public:
std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }
void addLane(Lane l) { incomlingLanes.push_back(l); }
private:
std::vector<Lane> incomingLanes;
};
The above is simplissime, and yet achieves the goal:
clients of the class cannot modify the vector itself
clients of the class cannot modify the vector content (Lane instances)
and of course, the class can access the vector content fully and modify it at will.
Your new main routine becomes:
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
b.getIncomingLanes().at(1).printLane();
b.getIncomingLanes().at(1).setA(12); // expected-error\
// { passing ‘const Lane’ as ‘this’ argument of
// ‘void Lane::setA(int)’ discards qualifiers }
return 1;
}
(*) This is weak in the sense that even though the attribute itself is not exposed, because we give a reference to it to the external world in practice clients are not really shielded.
I was writing a test case out to tackle a bigger problem in my application. I ended trying some code out on codepad and discovered that some code that compiled on my local machine (g++ 4.4.1, with -Wall) didn't compile on codepad (g++ 4.1.2), even though my local machine has a newer version of g++.
Codepad calls this a reference to reference error, which I looked up and found a litle information on. It looks like it's not a good idea to have a stl container of references. Does this mean I need to define my own PairPages class? And if this is the case, why did it compile locally in the first place? What's going on?
codepad link: http://codepad.org/UAaJI1rl
#include <deque>
#include <utility>
#include <iostream>
using namespace std;
class Page {
public:
Page() : number_(++count) {}
int getNum() const { return number_; }
private:
static int count;
int number_;
};
int Page::count = 0;
class Book {
public:
Book() : currPageIdx_(3) {
int numPages = 5;
while (numPages > 0) {
pages_.push_back(Page());
numPages--; // oops
}
}
pair<const Page&, const Page&> currPages() { return pagesAt(currPageIdx_); }
pair<const Page&, const Page&> pagesAt(int pageNo) { return make_pair(pages_[pageNo - 1], pages_[pageNo]); }
//const Page& currPages() { return pagesAt(currPageIdx_); }
//const Page& pagesAt(int pageNo);
private:
deque<Page> pages_;
int currPageIdx_;
};
int main() {
Book book;
cout << book.pagesAt(3).first.getNum() << endl;
cout << book.currPages().first.getNum() << endl;
}
A vector (or any STL container) of references is indeed a bad idea, as obvious when you simply look at requirements for element type T of any STL container (ISO C++03 23.1[lib.container.requirements]). It starts off by saying that "containers are objects that store other objects". We can stop right here, because a reference is not an object in C++ (unlike, say, a pointer; note that "object" in C++ parlance doesn't mean "instance of class"!). But, furthermore, it requires T to be Assignable, the requirements for which refer to type T& - if T is itself some reference type U&, then the constructed type would be U& &, which (reference to reference) is illegal in C++.
If you really want to have a container that doesn't manage lifetimes of objects, then you should use a container of pointers. If you prefer the safety of references (e.g. lack of pointer arithmetic and null value), you can use std::tr1::reference_wrapper<T> class, which is copy constructible and assignable wrapper for a reference.
On the poster's infinite loop problem: Your code loops indefinitely because in the Book constructor the counter numPages is never decreased, thus the while statement never halts until you run out of memory.
It's usually easier to spot these kind of errors by just using a for-loop:
Book() : currPageIdx_(3) {
for(int numPages = 0; numPages < 5; ++numPages) {
pages_.push_back(Page());
}
}