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

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.

Related

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.

Why is emplace_back failing even though the direct constructor works? [duplicate]

This question already has answers here:
Emplace an aggregate in std::vector
(3 answers)
Closed 4 years ago.
Why is it that I can call a constructor directly, but when I use exactly the same arguments in emplace_back, I get an error "No matching member function for call to 'emplace_back'"? To get the error, I need to be passing a list to the constructor. There must be something very simple going on here, but I can't find it in a search.
Here is a minimal example.
class A {
public:
A(std::list<double> c){
}
};
void test(){
A an_A = A({0.0}); //No error
std::list<A> list_of_As;
list_of_As.emplace_back({0.0}); //Error
}
The problem with {} is that it has several types it can describe. Now, when you don't specify the type, the compiler need to deduce which input type you ment to send, and it's unable to do that. For this reason you have to specify the type of the {}.
void test(){
A an_A = A({0.0});
std::list<A> list_of_As;
list_of_As.emplace_back(list<double>{0.0});
}
Another options:
for the next class:
class A {
public:
A(list<double> c, int a){
}
};
You can use:
list_of_As.emplace_back(list<double>{0.0}, 1);
//list_of_As.emplace_back(A({0.0}, 1)); <-- Avoid using this. Explanation is right after this section.
list_of_As.emplace_back(initializer_list<double>{0.0}, 1);
Emplace Vs Push
is there any good reason not to solve the problem with A({0.0}) rather than list{0.0} ?
Yes. emplace_back used for creating the objects of the list in place instead of copy/move them later to the list. There is no reason for using emplace_back like it was push_back. The right way to use emplace_back is to send it the arguments of the object's constructor, and not the object itself.
push_back will move your object into the list/vector if only it moved by reference (rvalue) and if the element type has a move assignment operator.
For more reading about move/copy and push_back/emplace_back

How to avoid deletion of object given as a parameter in C++

I am new to C++ and I do not know how to solve the following problem.
The class Foo has a constructor which creates a array of doubles of a given size. The destructor deletes this array. The print method prints the array.
#include <iostream>
class Foo {
private:
int size;
double* d;
public:
Foo(int size);
~Foo();
void print();
};
Foo::Foo(int size)
{
this->size = size;
d = new double[size];
for (int i = 0; i < size; i++)
{
d[i] = size * i;
}
}
Foo::~Foo()
{
delete[] d;
}
void Foo::print()
{
for (int i = 0; i < size; i++)
{
std::cout << d[i] << " ";
}
std::cout << std::endl;
}
Now I have a function func(Foo f) which does nothing.
void func(Foo f){}
int main()
{
Foo f(3);
f.print();
func(f);
Foo g(5);
f.print();
return 0;
}
Executing this code gives the following output:
0 3 6
0 5 10
Although I am printing f both times, somehow the values inside the array have changed.
I guess that the destructor of Foo is called on parameter Foo f after the execution of func(Foo f) and this frees the allocated memory for d, which is reallocated for Foo g(5). But how can I avoid this without using vectors or smart pointers?
The problem is with the design of the class. The default copy constructor will create a new instance of Foo when passed by value into the free standing function named func.
When the instance of Foo named f exits scope then the code invokes the user-provided destructor that deletes the array of doubles. This opens the code to the unfortunate situation of deleting the same array twice when the original instance of Foo named f exits scope at the end of the program.
When run on my machine, the code does not produce the same output. Instead I see two output lines of 0 3 6 followed by fault indicating the double free operation.
The solution is to avoid the copy by passing by reference (or by const reference): void func(Foo const &f) { } or to supply a valid copy constructor that makes a deep copy of the underlying array. Passing by reference is just a bandaid that avoids exercising the bug.
Using std::vector<double> fixes the problem because the default copy constructor will perform a deep copy and avoid double deallocation. This is absolutely the best approach in this small example, but it avoids having to understand the root of the problem. Most C++ developers will learn these techniques then promptly do what they can to avoid having to write code that manually allocates and deallocates memory.
You should probably pass the object as a reference func(Foo& f) or - if you do not want to modify it at all - as a constant reference func(const Foo& f). This will not create or delete any objects during the function call.
Aside from that, as others have already mentioned, your class should better implement the Rule of Three.
When you pass a value to a function, it is supposed to be copied. The destructor is run on the copy and should no effect on the original object. Foo fails to implement a copy constructor, so compiler provides the default one which simply performs a member-wise copy of the struct. As a result, the "copy" of Foo inside Func contains the same pointer as the original, and its destructor frees the data pointed to by both.
In order to be usable by idiomatic C++ code, Foo must implement at least a copy constructor and an assignment operator in addition to the destructor. The rule that these three come together is sometimes referred to as "the rule of three", and is mentioned in other answers.
Here is an (untested) example of what the constructors could look like:
Foo::Foo(const Foo& other) {
// copy constructor: construct Foo given another Foo
size = other->size;
d = new double[size];
std::copy(other->d, other->d + size, d);
}
Foo& Foo::operator=(const Foo& other) {
// assignment: reinitialize Foo with another Foo
if (this != &other) {
delete d;
size = other->size;
d = new double[size];
std::copy(other->d, other->d + size, d);
}
return *this;
}
Additionally, you can also modify functions like func to accept a reference to Foo or a constant reference to Foo to avoid unnecessary copying. Doing this alone would also happen fix the immediate problem you are having, but it would not help other issues, so you should definitely implement a proper copy constructor before doing anything else.
It's a good idea to get a good book on C++ where the rule of three and other C++ pitfalls are explained. Also, look into using STL containers such as std::vector as members. Since they implement the rule of three themselves, your class wouldn't need to.
One problem is that calling func creates a bitwise copy. When that copy goes out of scope the destructor is called which deletes your array.
You should change void func(Foo f){} to void func(Foo& f){}.
But better yet you add a create copy constructor or add a private declaration to stop it being called unexpectedly.

How to avoid destruction in Class [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I have a question that how i can avoid the destruction in class.
I have the sample code C++ here:
class Array {
int *p;
int n;
public:
Array(int n_ = 0) {
p = new int[n_];
}
~Array(void) {
cout << "Deleted" << endl; delete []p;
}
friend Array operator+(Array A, Array B) // the amount of elements A and B are the same
{
Array S(A.n);
for(int i=0; i < A.n; i++)
S.p[i] = A.p[i] + B.p[i];
return S; // object S has been destroyed before returned.
}
};
In here, when the object has got the value and return. But object S have been destroyed by destruction before returned. Can anyone help me to avoid the destruction or some way for the object S can be returned to main. Thanks
You can either define a move and/or a copy constructor (if it is not implicitly defined) and the value will be moved/copied before its destruction.
You can provide a copy ctor, than it will turn out that your compiler never call it, due to NRVO (named Return Value Optimization).
Read this wiki: http://en.wikipedia.org/wiki/Return_value_optimization
With C++11 o C++14, you can use the move semantics, a general technique to move expensive objects.

C++ Boost any attempt [duplicate]

This question already has answers here:
boost::any replacement for the code below
(2 answers)
Closed 8 years ago.
I don't have access to the Boost library and am trying to implement something similar to Boost any (a container that can store multiple types). I found an example at http://learningcppisfun.blogspot.co.uk/2007/09/boostany.html, however when I compile it I get a segmentation fault. Debugging it seems to suggest that it's Variant's destructor causing an issue. When I comment the destructor out it works fine -- although it's leaking memory. Can anyone explain what's happening? Thanks!
#include <iostream>
#include <vector>
using namespace std;
class BaseHolder
{
public:
virtual ~BaseHolder(){}
};
template<typename T>
class HoldData : public BaseHolder
{
public:
HoldData(const T& t_) : t(t_){}
T t;
};
class Variant
{
public:
template<typename T>
Variant(const T& t) : data(new HoldData<T>(t)){}
~Variant(){delete data;}
BaseHolder* data;
};
int main(){
vector<Variant> a;
int x = 10;
double y = 3.15;
a.push_back(x);
a.push_back(y);
cout << dynamic_cast<HoldData<int> *>(a[0].data)->t << endl;
cout << dynamic_cast<HoldData<double> *>(a[1].data)->t << endl;
return 0;
}
Output:
10
3.5
You have a basic violation of the rule of three.
You allocate in the default constructor, and de-allocate in the destructor. Now, what about your copy constructor and assignment operator? What about when two Variant objects point to the same data, and then they both go out of scope?
Since vectors maintain internal integrity by copying elements around and, in fact hold copies in the first place, it should be clear that this is a serious factor.
What I think is happening is this
You push int 10 onto the vector a
This triggers Constructor call for a temp Variant lets call this var1.
Constructor calls new HoldData (10)
Now vector a calls the Variant's copy constructor (which is automatically supplied by compiler) to create a Variant var2 in the vector. The default copy constructor is just a bitwise copy so var1 and var2 both have a data pointer pointing to same place.
var1 now goes out of scope and its destructor is called deleting its data pointer.
var2 in the vector now has a pointer to invalid memory. When vector a goes out of scope var2 will call its destructor and try to delete the memory a second time hence the crash.
You need to provide your own copy constructor in Variant that will safely copy the HoldData pointer.