I have found a very prejudicial fact about stl maps. For some reason I cant get objects being inserted in the map to get constructed/destructed only once.
Example:
struct MyObject{
MyObject(){
cout << "constructor" << endl;
}
~MyObject(){
cout << "destructor" << endl;
}
};
int main() {
std::map<int, MyObject> myObjectsMap;
myObjectsMap[0] = MyObject();
return 0;
}
returns:
constructor
destructor
destructor
constructor
destructor
If I do:
typedef std::pair<int, MyObject> MyObjectPair;
myObjectsMap.insert( MyObjectPair(0,MyObject()));
returns:
constructor
destructor
destructor
destructor
I'm inserting Objects responsible for their own memory allocation, so when destructed they'll clean themselves up, being destructed several times is causing me some trouble.
I suggest you add a copy constructor - that's what is being used for the 'missing' constructions I think.
Code:
#include <iostream>
#include <map>
using namespace std;
struct MyObject{
MyObject(){
cout << "no-arg constructor" << endl;
}
MyObject(const MyObject&) {
cout << "const copy constructor" << endl;
}
~MyObject(){
cout << "destructor" << endl;
}
};
int main() {
std::map<int, MyObject> myObjectsMap;
myObjectsMap[0] = MyObject();
return 0;
}
Output:
no-arg constructor
const copy constructor
const copy constructor
destructor
destructor
no-arg constructor
destructor
destructor
std::map is allowed to make as many copies of your objects as it wishes. This is implementation defined and you have no control over this. The "missing" constructions you notice, by the way, may be for calling the copy-constructor, which you didn't define.
What you can do, however is use a flyweight so constructing an object in fact fetches a existing object from a pool of pre-existing objects, and destructing an object does nothing. The pool never frees its objects, but it always maintains a handle over all of them. This way, your memory usage is large from start to stop, but it doesn't change much throughout the life of the program.
To be able to be used in a standard container your objects must be copyable and assignable. If your objects don't conform to this you may are likely to have problems.
That said, if (as your sample code indicates) you just need a default constructed object inserted in the map you can just use operator[] for its side effect:
// Insert default constructed MyObject at key 0
myObjectsMap[0];
Edit
I'm not quite clear from your question, but if you're unclear about the number of objects constructed and believe there is a constructor/destructor mismatch then note that the compiler will provide a copy constructor which doesn't log to std::cout as you don't provide a user-declared one.
When you say myObjectsMap[0], you are calling the default constructor for MyObject. This is because there is nothing in [0] yet, and you just accessed it. It's in the manual.
When you hit MyObject(); you are creating a temporary MyObject instance using the default constructor.
Because you allowed the compiler to define your copy constructor, you see more destructor than constructor messages. (There can only be one destructor, but many constructors, unlike building a house.) If you object should never be copied this way, then you likely want to declare a private copy constructor and copy assignment operator.
You're calling the default constructor and the copy constructor twice each with this code:
myObjectsMap[0] = MyObject();
When you do this:
myObjectsMap.insert( MyObjectPair(0,MyObject()));
you call the default constructor once and the copy constructor 3 times.
You should likely use pointers as map values instead of the objects themselves, in particular I suggest looking at shared_ptr.
note: tests were done using GCC 3.4.5 on a Windows NT 5.1 machine.
That's the way map and the other containers work, you can't get around it. That's why std::auto_ptr can't be used in a collection, for example.
Related
Consider the below code, where a composing class with another class as its member is being instantiated:
class CopyAble {
private:
int mem1;
public:
CopyAble(int n1) : mem1(n1) {
cout << "Inside the CopyAble constructor" << endl;
}
CopyAble(const CopyAble& obj) {
cout << "Inside the CopyAble copy constructor" << endl;
this->mem1 = obj.mem1;
return *this;
}
CopyAble& operator=(const CopyAble& obj) {
cout << "Inside the CopyAble assignment constructor" << endl;
this->mem1 = obj.mem1;
}
~CopyAble() {};
};
class CopyAbleComposer {
private:
CopyAble memObj;
public:
CopyAbleComposer(CopyAble m1) : memObj(m1) {
cout << "Composing the composer" << endl;
}
~CopyAbleComposer() {}
};
int main()
{
CopyAble ca(10);
CopyAbleComposer cac(ca);
return 0;
}
When I run this, I get the output:
Inside the CopyAble constructor
Inside the CopyAble copy constructor
Inside the CopyAble copy constructor
Composing the composer
Which means that the CopyAble copy constructor is being run twice - once when the CopyAble object is passed into the CopyAbleComposer constructor, and again when the initializer memObj(m1) runs.
Is this an idiomatic use of the copy constructor? It seems very inefficient that the copy constructor runs twice when we try to initialize a member object with a passed-in object of the same type, and it seems like a trap a lot of C++ programmers can easily fall into without realizing it.
EDIT: I don't think this is a duplicate of the question regarding passing a reference into the copy constructor. Here, we are being forced to pass a reference into a regular constructor to avoid duplicate object creation, my question was that is this generally known that class constructors in C++ should have objects passed in by reference to avoid this kind of duplicate copy?
You should accept CopyAble by reference at CopyAbleComposer(CopyAble m1), otherwise a copy constructor will be called to construct an argument. You should also mark it as explicit to avoid accidental invocations:
explicit CopyAbleComposer(const CopyAble & m1)
Pass-by-value and the associated copying is a pretty widely known property of C++. Actually, in the past C++ was criticized for this gratuitious copying, which happened silently, was hard to avoid and could lead to decreased performance. This is humorously mentioned e.g. here:
You accidentally create a dozen instances of yourself and shoot them all in the foot. Providing emergency medical assistance is impossible since you can't tell which are bitwise copies and which are just pointing at others and saying, "That's me, over there."
C++98
When any function/method is declared to receive an argument by value, this sort of copying happens. It doesn't matter if it's a constructor, a "stand-alone" function or a method. To avoid this, use a const reference:
CopyAbleComposer(const CopyAble& m1) : memObj(m1)
{
...
}
Note: even if you rearrange your code as below, one copy always remains. This has been a major deficiency in C++ for a long time.
CopyAbleComposer cac(CopyAble(10)); // initializing mem1 by a temporary object
C++11
C++11 introduced move semantics, which replaces the additional copy by a "move" operation, which is supposed to be more efficient than copy: in the common case where an object allocates memory dynamically, "move" only reassigns some pointers, while "copy" allocates and deallocates memory.
To benefit from optimization offered by move semantics, you should undo the "optimization" you maybe did for C++98, and pass arguments by value. In addition, when initializing the mem1 member, you should invoke the move constructor:
CopyAbleComposer(CopyAble m1) : memObj(std::move(m1)) {
cout << "Composing the composer" << endl;
}
Finally, you should implement the move constructor:
CopyAble(CopyAble&& obj) {
cout << "Inside the CopyAble move constructor" << endl;
this->mem1 = obj.mem1;
}
Then you should see that the "copy" message doesn't appear, and is replaced by the "move" message.
See this question for more details.
Note: In all these examples, the CopyAble objects are assumed to be much more complex, with copy and move constructors doing non-trivial work (typically, resource management). In modern C++, resource management is considered a separate concern, in the context of separation of concerns. That is, any class that needs a non-default copy or move constructor, should be as small as possible. This is also called the Rule of Zero.
In order to avoid duplication of elements, I'm building a class that holds elements and provide an acces to them.
My elements (DynLibrary) are movable but not copyable
class DynLibrary
{
public:
DynLibrary() : _handle(nullptr) {}
DynLibrary(const std::string& path) { DynLibrary::open(path); }
DynLibrary(const DynLibrary&) = delete;
DynLibrary(DynLibrary&&) = default;
~DynLibrary() { DynLibrary::close(); }
...
}
Those object are allocated in an unordered_map which key is the path that generated them.
I'm allocation them that way
class DynAllocator
{
public:
DynLibrary& library(const std::string& f)
{
if (_handles.find(f) == _handles.end())
{
std::cout << "#Emplace" << std::endl;
_handles.emplace(f, DynLibrary(f));
}
std::cout << "#Return" << std::endl;
return _handles.at(f);
}
private:
std::unordered_map<std::string, DynLibrary> _handles;
};
However when calling DynAllocator::library I get the following output:
#Emplace
close 0x1dfd1e0 // DynLibrary destructor
#Return
Which means that the object which is inserted has somehow been copied and the destructor of the copy just invalidated my object (calling dlclose with my handler)
Is my movable but not copyable approach of DynLibrary ok ?
How can I insert an instance of DynLibrary if my unordered_map without copy ?
Please note that I know how to do that using pointers / smart pointers (std::unique_ptr) but that i'd like to avoid them at all cost !
Which means that the object which is inserted has somehow been copied and the destructor of the copy just invalidated my object
No, that's not what that means. DynLibrary has a deleted copy constructor, so the code would not compile if that constructor were somehow chosen through overload resolution.
_handles.emplace(f, DynLibrary(f));
What's happening on the line above is you're creating a temporary DynLibrary object which is then move constructed into the unordered_map. If you wish to avoid this move construction, use std::piecewise_construct instead.
_handles.emplace(std::piecewise_construct,
std::forward_as_tuple(f),
std::forward_as_tuple(f));
Now you're directly constructing the DynLibrary object within the unordered_map and bypassing creation of the temporary.
As T.C. comments, the piecewise construction constructor is not necessary in this case because DynLibrary has a non-explicit converting constructor. You can achieve the same effect as above with
_handles.emplace(f, f);
I'm trying to understand some aspects of C++.
I have written this short programme to show different ways of returning objects from functions in C++:
#include <iostream>
using namespace std;
// A simple class with only one private member.
class Car{
private:
int maxSpeed;
public:
Car( int );
void print();
Car& operator= (const Car &);
Car(const Car &);
};
// Constructor
Car::Car( int maxSpeed ){
this -> maxSpeed = maxSpeed;
cout << "Constructor: New Car (speed="<<maxSpeed<<") at " << this << endl;
}
// Assignment operator
Car& Car::operator= (const Car &anotherCar){
cout << "Assignment operator: copying " << &anotherCar << " into " << this << endl;
this -> maxSpeed = anotherCar.maxSpeed;
return *this;
}
// Copy constructor
Car::Car(const Car &anotherCar ) {
cout << "Copy constructor: copying " << &anotherCar << " into " << this << endl;
this->maxSpeed = anotherCar.maxSpeed;
}
// Print the car.
void Car::print(){
cout << "Print: Car (speed=" << maxSpeed << ") at " << this << endl;
}
// return automatic object (copy object on return) (STACK)
Car makeNewCarCopy(){
Car c(120);
return c; // object copied and destroyed here
}
// return reference to object (STACK)
Car& makeNewCarRef(){
Car c(60);
return c; // c destroyed here, UNSAFE!
// compiler will say: warning: reference to local variable ācā returned
}
// return pointer to object (HEAP)
Car* makeNewCarPointer(){
Car * pt = new Car(30);
return pt; // object in the heap, remember to delete it later on!
}
int main(){
Car a(1),c(2);
Car *b = new Car(a);
a.print();
a = c;
a.print();
Car copyC = makeNewCarCopy(); // safe, but requires copy
copyC.print();
Car &refC = makeNewCarRef(); // UNSAFE
refC.print();
Car *ptC = makeNewCarPointer(); // safe
if (ptC!=NULL){
ptC -> print();
delete ptC;
} else {
// NULL pointer
}
}
The code doesn't seem to crash, and I get the following output:
Constructor: New Car (speed=1) at 0x7fff51be7a38
Constructor: New Car (speed=2) at 0x7fff51be7a30
Copy constructor: copying 0x7fff51be7a38 into 0x7ff60b4000e0
Print: Car (speed=1) at 0x7fff51be7a38
Assignment operator: copying 0x7fff51be7a30 into 0x7fff51be7a38
Print: Car (speed=2) at 0x7fff51be7a38
Constructor: New Car (speed=120) at 0x7fff51be7a20
Print: Car (speed=120) at 0x7fff51be7a20
Constructor: New Car (speed=60) at 0x7fff51be79c8
Print: Car (speed=60) at 0x7fff51be79c8
Constructor: New Car (speed=30) at 0x7ff60b403a60
Print: Car (speed=30) at 0x7ff60b403a60
Now, I have the following questions:
Is makeNewCarCopy safe? Is the local object being copied and destroyed at the end of the function? If so, why isn't it calling the overloaded assignment operator? Does it call the default copy constructor?
My guts tell me to use makeNewCarPointer as the most usual way of returning objects from a C++ function/method. Am I right?
Is makeNewCarCopy safe? Is the local object being copied and destroyed
at the end of the function? If so, why isn't it calling the overloaded
assignment operator? Does it call the default copy constructor?
The important question here is "Is makeNewCarCopy safe?" The answer to that question is, "yes." You are making a copy of the object and returning that copy by-value. You do not attempt to return a reference to a local automatic object, which is a common pitfall among newbies, and that is good.
The answers to the other parts of this question are philisophically less important, although once you know how to do this safely they may become critically important in production code. You may or may not see construction and destruction of the local object. In fact, you probably won't, especially when compiling with optimizations turned on. The reason is because the compiler knows that you are creating a temporary and returning that, which in turn is being copied somewhere else. The temporary becomes meaningless in a sense, so the compiler skips the whole bothersome create-copy-destroy step and simply constructs the new copy directly in the variable where it's ultimately intended. This is called copy elision. Compilers are allowed to make any and all changes to your program so long as the observable behavior is the same as if no changes were made (see: As-If Rule) even in cases where the copy constructor has side-effects (see: Return Value Optimization) .
My guts tell me to use makeNewCarPointer as the most usual way of
returning objects from a C++ function/method. Am I right?
No. Consider copy elision, as I described it above. All contemporary, major compilers implement this optimization, and do a very good job at it. So if you can copy by-value as efficiently (at least) as copy by-pointer, is there any benefit to copy by-pointer with respect to performance?
The answer is no. These days, you generally want to return by-value unless you have compelling need not to. Among those compelling needs are when you need the returned object to outlive the "scope" in which it was created -- but not among those is performance. In fact, dynamic allocation can be significantly more expensive time-wise than automatic (ie, "stack") allocation.
Yes, makeNewCarCopy is safe. Theoretically there will be a copy made as the function exits, however because of the return value optimization the compiler is allowed to remove the copy.
In practice this means that makeNewCarCopy will have a hidden first parameter which is a reference to an uninitialized Car and the constructor call inside makeNewCarCopy will actually initialize the Car instance that resides outside of the function's stack frame.
As to your second question: Returning a pointer that has to be freed is not the preferred way. It's unsafe because the implementation detail of how the function allocated the Car instance is leaked out and the caller is burdened with cleaning it up. If you need dynamic allocation then I suggest that you return an std::shared_ptr<Car> instead.
Yes makeNewCarCopy is safe. And in most cases it is effective as compiler can do certain optimizations like copy elision (and that the reason you do not see assignment operator or copy ctor called) and/or move semantics added by C++11
makeNewCarPointer can be very effective, but is is very dangerous at the same time. The problem is you can easily ignore return value and compiler will not produce any warnings. So at least you should return smart pointer like std::unique_ptr or std::shared_ptr. But IMHO previous method is more preferred and would be at least not slower. Different story if you have to create object on heap by different reason.
I have class like this
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
virtual ~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
}
And then I push instances into a std::vector like this:
stack.push_back(variable(0));
I expect that the destructor of variable will be called but the if won't enter until a value is assigned to type because I expect the constructor I provide will be called when the instance is copied into the vector. But for some reason it is not.
After calling stack.push_back the destructor (of the copy?) is ran and type has some random value like if the constructor was never called.
I can't seem to figure what I am doing wrong. Please help! ^_^
EDIT:
Ok here is a self contained example to show what I mean:
#include <iostream>
#include <vector>
class variable
{
public:
variable(int _type=0) : type(_type), value(NULL), on_pop(NULL)
{
}
~variable()
{
if (type)
{
std::cout << "Variable Deleted" <<std::endl;
on_pop(*this);
value=NULL;
}
}
int type;
void* value;
typedef void(*func1)(variable&);
func1 on_pop;
};
static void pop_int(variable& var)
{
delete (int*)var.value;
}
static void push_int(variable& var)
{
var.type = 1;
var.value = new int;
var.on_pop = &pop_int;
}
typedef void(*func1)(variable&);
func1 push = &push_int;
int main()
{
std::vector<variable> stack;
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
stack.push_back(variable(0));
push(stack[stack.size()-1]);
return 0;
}
The program above outputs the following:
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Variable Deleted
Process returned 0 (0x0) execution time : 0.602 s
Press any key to continue.
Welcome to RVO and NRVO. This basically means that the compiler can skip creating an object if it's redundant- even if it's constructor and destructor have side effects. You cannot depend on an object which is immediately copied or moved to actually exist.
Edit: The actual value in the vector cannot be ellided at all. Only the intermediate variable variable(0) can be ellided. The object in the vector must still be constructed and destructed as usual. These rules only apply to temporaries.
Edit: Why are you writing your own resource management class? You could simply use unique_ptr with a custom deleter. And your own RTTI?
Every object that was destructed must have been constructed. There is no rule in the Standard that violates this. RVO and NRVO only become problematic when you start, e.g., modifying globals in your constructors/destructors. Else, they have no impact on the correctness of the program. That's why they're Standard. You must be doing something else wrong.
Ultimately, I'm just not sure exactly WTF is happening to you and why it's not working or what "working" should be. Post an SSCCE.
Edit: In light of your SSCCE, then absolutely nothing is going wrong whatsoever. This is entirely expected behaviour. You have not respected the Rule of Three- that is, you destroy the resource in your destructor but make no efforts to ensure that you actually own the resource in question. Your compiler-generated copy constructor is blowing up your logic. You must read about the Rule of Three, copy and swap and similar idioms for resource handling in C++, and preferably, use a smart pointer which is already provided as Standard like unique_ptr which does not have these problems.
After all, you create six instances of variable- three temporaries on the stack, and three inside the vector. All of these have their destructors called. The problem is that you never considered the copy operation or what copying would do or what would happen to these temporaries (hint: they get destructed).
Consider the equal example of
int main()
{
variable v(0);
push_int(v);
variable v2 = v;
return 0;
}
Variable v is constructed and allocates a new int and everything is dandy. But wait- then we copy it into v2. The compiler-generated constructor copies all the bits over. Then both v2 and v are destroyed- but they both point to the same resource because they both hold the same pointer. Double delete abounds.
You must define copy (shared ownership - std::shared_ptr) or move (unique ownership - std::unique_ptr) semantics.
Edit: Just a quick note. I observe that you actually don't push into items until after they're already in the vector. However, the same effect is observed when the vector must resize when you add additional elements and the fundamental cause is the same.
The destructor is called 6 times. A constructor is called six times. Just not the one you intended.
Ok. I've been reading some more about the intrinsics of different containers and, apparently, the one that does the job I'm trying to accomplish here is std::deque.
I'm running into some strange problems when assigning the reference of a pointer to a variable: the local code works correctly, but it causes memory access errors elsewhere:
//This works fine
Gridcell* g = model.gc;
cout << g->LC_updated << " " << g << endl;
//When I include this, the program crashes elsewhere
//But output from this line is OK
Gridcell gc = *g;
cout << "Var:" << gc.LC_updated << &gc << endl;
(Gridcell is a class, which doesn't have a no-args constructor)
I'm not a C++ expert, and this is a fairly large external library, but I can't understand why an assignment to a locally scoped variable should cause problems elsewhere. Can anyone shed some light on this?
You don't give enough information to solve the problem. There is nothing inherently wrong with the code you've posted.
My guess is that Gridcell lacks a proper copy constructor and so when gc goes out of scope it deletes things that *g is still referring to.
This line of code:
Gridcell gc = *g;
is where the copy constructor is being invoked. It's essentially equivalent to saying this:
Gridcell gc(*g);
which invokes the Gridcell::Gridcell(const Gridcell &) constructor, otherwise known as the copy constructor. The copy constructor is special in that if you don't have one, the compiler will automatically generate one for you. The automatically generated one typically just invokes the copy constructor of each individual member variable, including the pointers. For basic types, like int or Foo *, the copy constructor simply makes an exact copy.
For example, if you have code like this:
class Foo {
public:
Foo() : msg_(new char[30]) { strcpy(msg_, "I'm Foo!"); }
~Foo() { delete [] msg_; }
private:
char *msg_;
};
void aFunction(Foo *aFoo)
{
Foo myfoo = *aFoo;
}
void anotherFunction()
{
Foo localfoo;
aFunction(&localfoo);
}
It will crash. localfoo will allocate character array. The line Foo myfoo = *aFoo will call the copy constructor which will make a straight copy of the pointer. Then the destructor for myfoo will be called and the memory will be freed. Then the destructor for localfoo will be called and the memory will be freed again, resulting in a crash on many systems.
You need to make sure that Gridcell has a proper copy constructor. This is only required if Gridcell manually manages resources, which almost never should be the case. If it the the case for you, you will need The Big Three.
If you need more specific help, post the class definition of Gridcell, along with constructors and destructor, if you have them.
If your intention is not to copy, you can use a reference:
Gridcell & gc = *g;
cout << "Var:" << gc.LC_updated << &gc << endl;
The usage is the same, but it will not create copy.
Is model.gc a local variable?
If so, when it goes out of scope it ceases to exist. And any pointers to it are no longer valid.
#Space_C0wb0y is right.
Imagine that you have attributes in your Gridcell class that are pointers (arrays or objects that are explicitly allocated through new).
When you assgin an object of type Gridcell from another one, the default copy constructor makes a shallow copy. It copies the value of those pointers, but does not create new objects/arrays for the new attributes of yout new object.
If you split
cout << "Var:" << gc.LC_updated << &gc << endl;
in two lines:
cout << "&gc" <<&gc << endl;
cout << "Var:" << gc.LC_updated << endl;
You will probably see that the fault goes to the line where your reference LC_updated (I don't know what is it).
Check your constructors to see how it is being initialized.
This line:
GridCell gc = *g;
Does a copy of the instance pointed by g. If the GridCell does not define a copy-constructor (a constructor of signature GridCell(const GridCell& other)), then a default one is provided by the compiler that does a copy of each member. For member that are of a pointer type, this is just a copy of the pointer, and thus both gc and the instance pointed by g will point to the same memory.
When the gc variable goes out of scope, its destructor is called. If the GridCell class does manage some memory, does not provide a copy-constructor (or it is incorrect), and release the memory in its destructor, then the GridCell instance pointed by g will point to released memory after this point.
Generally, when a class manage some memory, it must override the destructor, the copy-constructor and the assignment operator. This is the rule of three.
Please note that the assignment will also perform slicing if g point to a subclass of GridCell and that can also bring other problems. If you want to use the gc variable as an alias not to have to use *g everywhere, you should consider using a reference (or a const-reference) instead of making a copy (especially if the object does manager lots of memory, copy can be expensive).