I'm trying const_string lib that looks not bad, but it crashes at runtime with access violation(atomic_count, operator++()). The test code:
#include <boost/const_string/const_string.hpp>
#include <boost/const_string/concatenation.hpp>
typedef boost::const_string<wchar_t> wcstring;
class Test
{
private:
const wcstring &s1;
const wcstring &s2;
public:
Test()
: s1(L"")
, s2(L"")
{
}
const wcstring &GetS1()
{
return s1;
}
const wcstring &GetS2()
{
return s2;
}
};
Test t;
int _tmain(int argc, _TCHAR* argv[])
{
//Test t;
wcstring t1 = t.GetS1(); // crashes here
wcstring t2 = t.GetS2();
return 0;
}
It crashes only if t is global. If I move declaration into main(), it's ok.
System: VS 2010, boost v. 1.47.0
The question: Am I doing something wrong or is it problem of library / compiler?
Can someone recommend a more stable implementation of immutable strings for C++?
Your instance of Test has initialized its reference data members as references to temporaries created from the literals L"".
Oops. The temporaries no longer exist by the time you try to use one of them in the copy constructor of wcstring at the line that crashes, so your references don't refer to anything.
I think boost::const_string should pretty much always be used by value, that's what it's for.
Related
Digging through MSDN, I ran into just another curious line:
// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }
The full example is buried here: https://msdn.microsoft.com/en-us/library/dd293668.aspx Refined to bare minimum, it looks like this:
#include <iostream>
const int f() { return 0; }
int main() {
std::cout << f() << std::endl;
return 0;
}
A few other tests with different return types demonstrated that both Visual Studio and g++ compile lines like this without a warning, yet const qualifier seems to have no effect on what I can do with the result. Can anyone provide an example of where it matters?
you can not modify the returned object
example:
#include <string>
using namespace std;
const string foo(){return "123";}
string bar(){return "123";}
int main(){
//foo().append("123"); //fail
bar().append("123"); //fine
}
This is almost the same as const variable
#include <string>
using namespace std;
const string foo = "123";
string bar = "123";
int main(){
//foo.append("123"); //fail
bar.append("123"); //fine
}
It is part of the return type. The functions return const string and const int.
In the case of const int, this indeed makes no difference compared to int, because the only thing you can do with an int return value is to copy the value somewhere (in fact, the standard explicitly says that const has no effect here).
In the case of const string, it does make a difference, because a return value of class type can have member functions called on it:
fourth().erase(1);
will fail to compile in the case that fourth() returns a const string, because erase() is not a const method (it tries to modify the string it is called on).
Personally, I never make value-returning functions return a const value, as it unnecessarily constrains the caller (although some people feel that it is useful to prevent writing things like string s = fourth().erase(1);).
As a learning exercise I am building a class to manage the old familiar argc and argv values to main. I am storing argv as a std::vector of std::strings. For the moment I would like to loop over my object as if it was the vector. The problem I'm having is that my solution becomes highly dependent on my choice of container and the compiler breaks when I try to fix it. Observe:
This is the way I would like my class to work for this example.
int main(int argc, char* argv) {
CLI options(argc, argv);
for (auto option : options) {
cout << option << endl;
}
}
This is fairly trivial, but did require a moment of research. Here is my header file
typedef char* cstring;
class CLI {
std::vector<std::string> arguments;
public:
CLI(const int argc, const cstring argv[]);
std::vector<std::string>::const_iterator begin();
std::vector<std::string>::const_iterator end();
};
and my source file for the CLI class. (minus includes etc)
CLI::CLI(const int argc, const cstring argv[]) {
arguments = std::vector<std::string>(argv, argv + argc);
}
std::vector<std::string>::const_iterator CLI::begin() {
return arguments.begin();
}
std::vector<std::string>::const_iterator CLI::end() {
return arguments.end();
}
This works beautifully, but here is my first problem. If I decide that I wish to use a linked list instead of a vector, I now have at least five spots that need to change, more if my client code is having a silly day and doesn't use auto for its loop (or whatever else it does). This feels like it should be a case of auto-to-the-rescue! With the new C++ features I should be able to change the method signature to this:
... // Header
auto begin();
... // Source
// Possibly without the decltype now? Not sure how or when...
auto CLI::begin() -> decltype(arguments.begin()) {
return arguments.begin();
}
This is where I finally get an error:
.../main.cpp: In function ‘int main(int, char**)’:
.../main.cpp:10:22: error: use of ‘auto CLI::begin()’ before deduction of ‘auto’
for (auto option : options) {
^
.../main.cpp:10:22: error: invalid use of ‘auto’
Okay. If I had to guess as to what this meant, I would say the auto in the for loop is looking up the signature for the begin method, hoping to find a concrete return type. What it finds instead is auto, and panics.
So, is this theory correct, and is there a better way to hide the container type despite the iterators?
P.S. The more I look at this problem, the more I am realizing that this functionality is probably not functionality I want in the final product anyways. But this still seems like an opportunity to learn something.
Since the header does not include code, the compilation unit for main.cpp cannot deduce the meaning of auto for begin()
This would work better for what you intend:
Header.h
#include <vector>
class A {
public:
std::vector<int> a;
decltype(a.begin()) begin();
decltype(a.cbegin()) cbegin() const;
};
Header.cpp
#include "header.h"
decltype(A::a.begin()) A::begin() {
return a.begin();
}
decltype(A::a.cbegin()) A::cbegin() const {
return a.cbegin();
}
main.cpp
#include "header.h"
int main(int argc, char **argv) {
A a;
auto b = a.begin();
auto cb = a.cbegin();
return 0;
}
A note on const safety: remember that a "const_iterator" is a unique type that is not necessarily const itself but that the object it represents is const. This means that the type is different which prevents you from returning a.begin() inside of a const function. The naive might try adding const decltype(a.begin()) return type but that is still not a vector::const_iterator but rather a const vector::iterator.
While trying to find out a problem that occurs only in a release build and not in the debug build I noticed the following behaviour (String would be invalid and would not point to anything while the int would be fine). I have given code below which gives an idea of what I was going through
typedef boost::shared_ptr<MyClass> shared_cls
typedef std::deque<shared_cls> vector_def;
typedef boost::shared_ptr<vector_def> shared_vector_def;
typedef boost::unordered_map<int,shared_vector_def> inner_map_def;
typedef boost::shared_ptr<inner_map_def> shared_inner_map_def;
static boost::unordered_map<std::string,shared_inner_map_def> bcontainer;
shared_cls& SomeMethod(const std::string& symb,const int& no)
{
shared_inner_map_def tshare = bcontainer[symb];
shared_vector_def tmp = tshare->at(no);
shared_cls t = tmp->back();
return t
}
The object MyClass looks like this
class SomeClass
{
private:
int i;
std::string s;
void set_i(int rx)
{
i = rx;
}
int get_i()
{
return i;
}
void set_s(std::string rx)
{
s = rx;
}
std::string get_s()
{
return s;
}
}
Now when I use the above method as in the following code
void main()
{
shared_cls r = SomeMethod("IBM",12);
//Here r does not have a valid string s
//However it does have a valid int i
}
Now my question is in the above main when I call the SomeMethod the r returned does not have a valid string s. It has a scrambled value I found this out by using a logger. However the value of s is totally find during the function SomeMethod. I resolved this issue by not returning the shared pointer by reference.In that case it works. Why does removing the reference make it work
Your shared_cls t goes out of scope because it is defined in the function SomeMethod itself. You need to return shared pointers by value if they are defined in the scope. In the link, it is explained why it is dangerous to return the reference of a temporary object.
In the case of std::string, string has a reference counting mechanism and when it's reference is decremented to zero, it becomes invalidated and a segmentation fault may be observed in such a case. Even if member int i is returned properly, it is still undefined behavior.
I use an unordered_map in my current C++ project and have the following problem:
When I insert a pair of objects into the unordered_map, the programm breaks and Windows shows me it's "[...].exe has stopped working", without giving me any information on the console (cmd). Some example code:
#include <unordered_map>
#include <network/server/NetPlayer.h>
#include <gamemodel/Player.h>
int main(int argc, char **argv) {
NetGame game;
boost::asio::io_service io_service;
NetPlayerPtr net(new NetPlayer(io_service, game));
PlayerPtr player(new Player);
std::unordered_map<PlayerPtr, NetPlayerPtr> player_map;
// Here it breaks:
player_map[player] = net;
return 0;
}
What I already tried:
I tried wrapping the line with a try-catch, but without success.
Details about the code:
NetPlayerPtr and PlayerPtr are boost::shared_ptr objects, the former contains some boost::asio objects like io_service and socket, the latter contains several custom objects.
I'm compiling with MinGW gcc with C++11 enabled on a 64bit Windows.
If more details are needed, please ask.
Okay, let's look at the code you linked to:
namespace std
{
template<>
class hash<Player>
{
public:
size_t operator()(const Player &p) const
{
// Hash using boost::uuids::uuid of Player
boost::hash<boost::uuids::uuid> hasher;
return hasher(p.id);
}
};
template<>
class hash<PlayerPtr>
{
public:
size_t operator()(const PlayerPtr &p) const
{
return hash<PlayerPtr>()(p); // infinite recursion
}
};
}
You have an inifinite recursion in your hash<PlayerPtr>::operator(). What you probably want is:
return hash<Player>()(*p);
or:
return hash<Player*>()(p->get());
depending on whether you want to identify the player by its internal id or its address.
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());
}
}