C++98/C++03 STL set bug? - c++

all,
One weird thing happens when I'm using set:
Let's say:
struct A {
int num;
bool operator<(const A& x) const
{
return num < x.num;
}
};
struct B {
set<A> ASet;
};
struct C {
list<B> BList;
list<B>::iterator BListIter;
C()
{
BList.push_back(B());
BListIter = --(BList.end());
}
};
somewhere we can have this code:
list<C> CList;
CList.push_back(C());
list<C>::iterator CListIter = --(CList.end());
for (...) {
A a = ...;
...
CListIter->BListIter->ASet.insert(a);
this will end up with segmentation fault after a few iterations. When this happens, I found an invalid item is referenced and compared (its address is 0x0000001b, so definitely wrong) during the insertion.
Funny thing is when I turn on -std=c++0x this option to use C++11 the problem goes aways! So I wonder if this is a bug of STL set in C++98/C++03?
Thanks,
Kevin

In C++03 or earlier, copies of the temporary objects are put on CList and the BList inside the CList object.
When the C::BList member is copied, a completely new list<B> is created, but when the C::BListIter member is copied, the new C::BListIter iterator still refers to the C::BList list in the original C object - which is a temporary that gets destroyed. So that iterator refers to an element of a destroyed list.
In C++11 move constructors are used instead of copy constructors, so the resulting iterator doesn't refer to a dead object.

Related

inserting object with no default ctor to std::map [duplicate]

This question already has answers here:
Why does the C++ map type argument require an empty constructor when using []?
(6 answers)
Closed 4 years ago.
class A
{
public:
A(int i)
{
x = new int(i);
}
~A()
{
if (x != NULL)
{
delete x;
x = NULL;
}
}
private:
A();
int *x;
};
void f()
{
{
map<int,A> myMap;
A a(2);
// myMap[7] = a; // cannot access default ctor
pair<int, A> p(7,a);
myMap.insert(p);
}
}
The problem here is that upon scope exit the destructor of A is called twice. Probably the first time to destruct A a(2) and the 2nd time to destruct some temp object created by map. This causes an exception since x is not allocated.
Why does the command myMap[7] = a construct a new A and why does it use the default ctor?
What can be a solution?
Because the subscript operator returns a reference to an element in the map, which you then assign to. In order to have an object to refer to, and assign to, that element must be constructed (unless an element already happens to exist for the given key).
a. To avoid the copy: emplace the A directly into the map instead of copying a local variable.
b. While getting rid of unnecessary copies is a good thing, it is not a substitute to fixing your class. Either make the class have well defined behaviour after assignment and copying, or make the class non copyable and non assignable. For more info, see rule of three (five).
You should never have bare owning pointers. Using a unique pointer instead would fix the class in an elegant way.

When std::vector push_back() the object which has the reference member

#include <iostream>
#include <vector>
class myClass {
public:
double a;
double& ref;
myClass() : ref(a)
{
a = 1;
}
~myClass() {}
};
using namespace std;
int main()
{
vector<myClass> myVector;
int nIter = 5;
while (nIter--) {
myVector.push_back(myClass());
}
return 0;
}
Hi.
I have myClass and I would like to push_back the myClasses and bring them together in one vector.
But unfortunately, I have to use a reference in myClass.
The problem is when the temporary object destructs, the reference becomes invalid and vector contains the object whose reference is invalidated.
After investigating, I was able to see that those reference variables are pointing at (referencing) the same memory.
I would like to find the way where each vector's element's reference member variable references each vector's element's a(member variable).
Is there any way to achieve this..?
Addition
I would like to describe my situation further.
I have one middle-sized project. In there, the users have the option to choose which variable among member variables will be used in my algorithm. so I made the script in which ref variable is used so that it can change according to the option.
I hope my explanation was clear.
You're getting this behavior because you are initializing your 'ref' member to a value that is on the stack, then the default copy constructor is copying that into the vector.
For example, in my debugger the value I have for ref is:
+ &myVector[1].ref 0x00eff80c {2.0000000000000000} double *
+ &myVector[1] 0x00126940 {a=2.0000000000000000 ref=2.0000000000000000 }
+ myVector { size=0x00000002 } std::vector<myClass,std::allocator<myClass> >
+ &nIter 0x00eff8f0 {0xffffffff} int *
You can see that myVector[1].ref is not inside myVector[1] as you'd expect, and is, in fact, on the stack. You can see that nIter and ref are only 57 bytes apart:
&nIter - (int*)&myVector[0].ref 57
If you want to see how this is implicitly happening you can delete your copy constructor:
myClass(myClass const &rhs) = delete;
inside myClass and you'll get an error at push_back.
Another option is to write your own copy constructor:
myClass(myClass const &rhs) : ref(a) {
a = rhs.a;
}
If you debug this you'll see that the values are correct, and that the memory locations of each ref are now inside the bounds of the myClass objects.
Finally you might be able to use emplace_back instead of push_back, which will construct myClass directly in the vector's memory instead of calling the copy ctor, though I wouldn't recommend this as it leaves this ref copy bug.
also don't forget the assignment operator if you go the copy ctor route:
https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
e.g.
myClass baz;
baz = myVector[0];
this will invoke operator= and not the copy ctor. My compiler (visual studio c++ latest) automatically deletes operator= if you declare a copy ctor, so it would catch this, but your compiler may not.

Is it possible to return a std::initializer_list from a function?

The following works:
struct A {
int i;
int v;
};
std::initializer_list<A> getList() {
return {A{0,1}, A{2,3}};
}
int main() {
auto list = getList();
}
I can verify that the contents of list is correct.
However, if I change the member v to a std::vector, it does not work:
struct A {
int i;
std::vector<int> v;
};
std::initializer_list<A> getList() {
return {A{0,{1,2}}, A{3,{4,5}}};
}
in this case, the returned list contains junk values.
I know the standard says that the underlaying objects are not copied when a std::initializer_list is copied. Is this what happens here?
Why did it work in the first example? Was it luck? Is it something special with the case when the objects in the list contains a std::vector?
Returning initializer_list compiles, but it seldom does the right thing. The list is a temporary value and the initializer_list object points to it. It is a dangling pointer.
In your first example, an optimization is applied because the list is a constant expression. Instead of being written into temporary storage, it is a static global. However, this optimization is not specified in the standard. The return value working, is only a form of undefined behavior.

Accessing map of class A from class B

I have two classes class A and class B. Class A has a map of type map<int,int>.
In class A, i have the following definition,
typedef std::map<int, int> mymap;
mymap MYMAP;
A A_OBJ;
// did some insert operations on A_OBJ's MYMAP
I also have the following function in class A that when invoked by B will return A's MYMAP as a copy to class B.
A::mymap A::get_port(){
// Returns A's map
return this -> MYMAP;
}
In class B,
void B::initialize_table(){
A::mymap port_table = A_OBJ.get_port();
cout<< "size of ports table at A is"<<port_table.size());
}
Code got compiled with out any issue. The only problem is that even if I insert some data to A's map, B always shows that A's map has 0 elements.
I have a timer at B which calls initialize_table() every 2s and it is supposed to get the latest copy of the map from A. Not sure where it went wrong.
Any help is appreciated. Thanks.
You're correct that you're creating a copy of the std::map. The way to fix this is by initializing a reference to the map.
Consider the following stub:
#include <iostream>
#include <map>
using my_map = std::map<int, int>;
struct A {
A() : m() {}
my_map& get_my_map() { return m; }
my_map m;
};
struct B {
B() : a() {}
void initialize_map_ref();
void initialize_map_val();
void print_index_42() { std::cout << a.get_my_map()[42] << '\n'; }
A a;
};
void B::initialize_map_ref() {
// notice this is a reference
my_map& m = a.get_my_map();
m[42] = 43;
}
void B::initialize_map_val() {
// notice this is a copy
my_map m = a.get_my_map();
m[42] = 43;
}
int main() {
B b;
b.initialize_map_ref();
b.print_index_42();
return 0;
}
B::initialize_map_ref initializes a reference (i.e., a reference to the map within a), where B::initialize_map_val creates a copy and initializes the copy. The copy dies after the call, so outside of the call, m[42] == 0. The reference initialization, on the other hand, persists because you've changed a reference to the underlying object.
Ideone: With reference and with value.
I suggest returning by an R-value reference for the sake of efficiency (i.e. A::mymap&& A::get_port(){return A::mymap(this -> MYMAP;) };).
I can only see your code failing in one of two circumstances:
you are updating A_OBJ.MYMAP after you call A_OBJ.get_port()
This will cause the copy to be out of date.
or you are updating A_OBJ.get_port(). and then calling A_OBJ.get_port() again. This will cause the copy to be modified but the original map, to be left unmodified, resulting in the second call to A_OBJ.get_port() to not consider any changes made to the value returned by the previous.
Depending on what you want you may want to return a (const) reference to the map.
EDIT I mistakenly originally thought that A::mymap port_table = A_OBJ.get_port(); would cause two copies, but now I realize it will cause a copy and then a move, it would also do that in the rvalue case, however that is likely to introduce undefined behaviour (I think) because of returning a reference to a temporary... (originally I had it return this -> MYMAP but would be an error as it would try to bind an lvalue (this -> MYMAP) to an rvalue reference)

c++ translate from dynamic allocation to references

I have following code:
class A{
public:
virtual do_something() = 0;
}
class B : public A{
public:
virtual do_something() override;
}
void use_a(A *a){
if (a){
a->do_something();
delete a;
}
}
use_a( new B() );
How this can be translated to references?
Notice do_something() is not const method.
I thought it can be something like this:
void use_a(A &&a){
a->do_something();
}
use_a( B() );
but someone told me this is bad style and must be avoided.
Rvalue references have move sematics. That does not work well when moving B as A.
Use lvalue reference:
void use_a(A &a);
B b;
use_a(b);
or a template:
template <typename T>
void use_a(T &&a);
or, if it doesn't need to be a reference, a smart pointer:
void use_a(std::unique_ptr<A> a);
void use_a(std::shared_ptr<A> a);
Quite simply you convert from a pointer to a reference by providing a concrete instance, i.e. you dereference:
void f(int& i);
f(*(new int)); // do not do this!
The problem is that raw pointers in C++ are precisely that - they do not have automatic lifetime scope, and by converting to an lvalue reference, you have suggested a contract that the instance is concrete and should not be destroyed by the receiver.
int* ptr = new int;
f(ptr);
delete ptr; // otherwise it leaked
Modern C++ uses RAII to provide controlled automatic lifetime management, and C++11 introduced unique_ptr and shared_ptr for handling pointers. With C++14 we also have the mechanisms to avoid raw pointers entirely.
std::unique_ptr<int> ptr = std::make_unique<int>(/* ctor arguments here */);
f(ptr.get());
// now when ptr goes out of scope, deletion happens automatically.
See also http://en.cppreference.com/w/cpp/memory/unique_ptr
Only one std::unique_ptr should have the address of a given allocation at any time (it assumes ownership and will delete the allocation on exiting scope if it's not released).
For a ref-counted pointer: http://en.cppreference.com/w/cpp/memory/shared_ptr
--- EDIT ---
Based on the OPs comments:
Firstly note that
Pair p = { "one", "two" };
// and
Pair p("one", "two");
Pair p{"one", "two"};
are synonymous, in all cases they create a stack-local variable, p, by allocating stack space and calling Pair::Pair("one", "two") to construct a Pair object there.
Remember, however, that this is a stack variable - it has an automatic lifetime and will expire at the end of the current scope.
{ Pair p{"one", "two"}; list_add(list, p); } //p is destroyed
In theory, you can replace this with
list_add(list, Pair{"one", "two"});
But what matters is whether list_add expects you to keep the object around until you remove it from the list... That is often what a list-based function that takes a pointer is expecting. If it takes a non-const reference, it may do the same.
To answer your original post::
struct A { virtual void doSomething() {} };
struct B : public A { virtual void doSomething() override() {} };
void useDoSomethingInterface(A& a) {
a.doSomething();
}
int main() {
A a;
B b;
useDoSomethingInterface(a);
useDoSomethingInterface(b);
}
consider the following:
void list_add(IList& list, Pair& pair) {
pair.next = list.head;
list.head = &pair; // << BAD NEWS
}
void badness(IList& list) {
list_add(list, Pair("hello", "world"));
}
void caller() {
IList list;
badness(list);
// list.head now points to a destroyed variable on the stack
C-pointers in C++ are raw, machine level pointers. They don't ref count. And C++ object instances have a fixed well defined lifetime: till the end of the scope.
However, if list_add is taking its data by value
void list_add(IList& list, Pair pair)
Then we'll be ok. The temporary Pair we create will have to be copied once to create pair and then copied again into the list, which is a shame but at least it won't crash.
your code is a bit unsafe.
first, what if a is null? you didn't check it.
second, what if a points to a stack-object or data-segment-object? you'll have unexpected behaviour (=crash on most of the OS).
if your object has to be dynamically alocated, just use std::shared_ptr
void use_a(std::shared_ptr<A>& a){
a->do_something();
}