Erase all members of a class - c++

Yesterday I read some code of a colleague and came across this:
class a_class
{
public:
a_class() {...}
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
a_class a_instances[10];
void some_function()
{
do_stuff();
do_more_stuff();
memset(a_instances, 0, 10 * sizeof(a_class)); // <===== WTF?
}
Is that legal (the WTF line, not the public attributes)? To me it smells really, really bad...
The code ran fine when compiled with VC8, but it throws an "unexpected exception" when compiled with VC9 when calling a_instances[0].event_more_values.push_back(whatever), but when accessing any of the other members. Any insights?
EDIT: Changed the memset from memset(&a_instances... to memset(a_instances.... Thanks for pointing it out Eduard.
EDIT2: Removed the ctor's return type. Thanks litb.
Conclusion: Thanks folks, you confirmed my suspicion.

This is a widely accepted method for initialization for C structs.
In C++ it doesn't work ofcourse because you can't assume anything about vectors internal structure. Zeroing it out is very likely to leave it in an illegal state which is why your program crashes.

He uses memset on a non-POD class type. It's invalid, because C++ only allows it for the simplest cases: Where a class doesn't have a user declared constructor, destructor, no virtual functions and several more restrictions. An array of objects of it won't change that fact.
If he removes the vector he is fine with using memset on it though. One note though. Even if it isn't C++, it might still be valid for his compiler - because if the Standard says something has undefined behavior, implementations can do everything they want - including blessing such behavior and saying what happens. In his case, what happens is probably that you apply memset on it, and it would silently clear out any members of the vector. Possible pointers in it, that would point to the allocated memory, will now just contain zero, without it knowing that.
You can recommend him to clear it out using something like this:
...
for(size_t i=0; i < 10; i++)
objects[i].clear();
And write clear using something like:
void clear() {
a_object o;
o.swap(*this);
}
Swapping would just swap the vector of o with the one of *this, and clear out the other variables. Swapping a vector is especially cheap. He of course needs to write a swap function then, that swaps the vector (even_more_values.swap(that.even_more_values)) and the other variables.

I am not sure, but I think the memset would erase internal data of the vector.

When zeroing out a_instances, you also zero out the std_vector within. Which probably allocates a buffer when constructed. Now, when you try to push_back, it sees the pointer to the buffer being NULL (or some other internal member) so it throws an exception.
It's not legitimate if you ask. That's because you can't overload writing via pointers as you can overload assignment operators.

The worst part of it is that if the vector had anything in it, that memory is now lost because the constructor wasn't called.
NEVER over-write a C++ object. EVER. If it was a derived object (and I don't know the specifics of std::vector), this code also over-writes the object's vtable making it crashy as well as corrupted.
Whoever wrote this doesn't understand what objects are and needs you to explain what they are and how they work so that they don't make this kind of mistake in the future.

You shouldn't do memset on C++ objects, because it doesn't call the proper constructor or destructor.
Specifically in this case, the destructor of even_more_values member of all a_instances's elements is not called.
Actually, at least with the members that you listed (before /* and so on */), you don't need to call memset or create any special destructor or clear() function. All these members are deleted automatically by the default destructor.

You should implement a method 'clear' in your class
void clear()
{
value1=0;
value2=0;
value_3=0f;
even_more_values.clear();
}

What you have here might not crash, but it probably won't do what you want either! Zeroing out the vector won't call the destructor for each a_class instance. It will also overwrite the internal data for a_class.even_more_values (so if your push_back() is after the memset() you are likely to get an access violation).
I would do two things differently:
Use std::vector for your storage both in a_class and in some_function().
Write a destructor for a_class that cleans up properly
If you do this, the storage will be managed for you by the compiler automatically.
For instance:
class a_class
{
public:
a_class() {...}
~a_class() { /* make sure that even_more_values gets cleaned up properly */ }
int some_method(int some_param) {...}
int value_1;
int value_2;
float value_3;
std::vector<some_other_class*> even_more_values;
/* and so on */
}
void some_function()
{
std::vector<a_class> a_instances( 10 );
// Pass a_instances into these functions by reference rather than by using
// a global. This is re-entrant and more likely to be thread-safe.
do_stuff( a_instances );
do_more_stuff( a_instances );
// a_instances will be cleaned up automatically here. This also allows you some
// weak exception safety.
}
Remember that if even_more_values contains pointers to other objects, you will need to delete those objects in the destructor of a_class. If possible, even_more_values should contain the objects themselves rather than pointers to those objects (that way you may not have to write a destructor for a_class, the one the compiler provides for you may be sufficient).

Related

How To Destruct Destructor-less Types Constructed via 'Placement New'

So I have built class with which I intended to use std::aligned_storage to store different types up to 16 bytes in for a 'Variant' class. Theoretically it should be able to store any POD type and common containers such as std::string and std::map.
I went by the code example found here, and it seemed like it was made for exactly what I was looking for: http://en.cppreference.com/w/cpp/types/aligned_storage
My version, basically:
class Variant {
public:
Variant() { /* construct */ }
Variant(std::map<int,int> v) {
new(&m_data) std::map<int,int>(v); // construct std::map<int,int> at &m_data
m_type = TYPE_MAP;
}
~Variant() {
if (m_type == TYPE_MAP) {
// cool, now destruct..?
reinterpret_cast<std::map<int, int>*>(&m_data)->~/*???????????????*/();
}
}
private:
// type of object in m_data
enum Type m_type;
// chunk of space for allocating to
std::aligned_storage<16, std::alignment_of<std::max_align_t>::value>::type m_data;
};
My problem comes with the destruction. As you can see at /*???????????????*/, I'm not sure what to call in place of ~T() in the cppreference.com example:
reinterpret_cast<const T*>(data+pos)->~T(); // I did the same thing except I know what T is, is that a problem is it?
In my mind, I'm doing exactly the same thing, disregarding template anonymity. Problem is, std::map doesn't have any std::map::~map() destructor method, only a std::map::~_Tree, which is clearly not intended for direct use. So, in the cppreference.com example code, what would ~T() be calling if T was an std::map<int,int>, and what is the proper way for me to call the destructor for an object with a known type in std::aligned_storage? Or am I over complicating things and are the clear() methods in these STL containers guaranteed do the equivalent of full destruction's?
Or, is there any simpler way around this? As I've possibly misunderstood something along the way regarding my intended usage of std::aligned_storage.
It sounds like you have read the header file where std::map is defined and think that std::map has no destructor because you could not find the declaration of a destructor.
However, in C++, a type that doesn't have a destructor declared will have a destructor implicitly declared by the compiler. This implicit destructor will call the destructors of bases and non-static members. It sounds like the std::map in your library implementation is a thin layer over _Tree. Therefore, all that needs to be done to destroy the map is to destroy the tree. Therefore, the compiler's default destructor does the trick.
It is allowed to write ->~map() in your case, and it will call the implicitly defined destructor, and the map will be destroyed correctly. You may also use this syntax with scalar types such as int (but not arrays, for some reason).
I'm not sure what to call in place of ~T()
Your type, which is named map:
reinterpret_cast<std::map<int, int>*>(&m_data)->~map();
Which if it makes you feel better you can put in a function template:
template <class T>
void destroy_as(void* p) {
static_cast<T*>(p)->~T();
}
destroy_as<std::map<int, int>>(&m_data);
Problem is, std::map doesn't have any std::map::~map() destructor method
It may be compiler generated, but the type assuredly has a destructor. All types have destructors. Some may be explicitly or impleted deleted, but they exist.
Note that your aligned_storage is too small to store a map, sizeof(std::map) is larger than 16.

What happens if an object resizes its own container?

This is not a question about why you would write code like this, but more as a question about how a method is executed in relation to the object it is tied to.
If I have a struct like:
struct F
{
// some member variables
void doSomething(std::vector<F>& vec)
{
// do some stuff
vec.push_back(F());
// do some more stuff
}
}
And I use it like this:
std::vector<F>(10) vec;
vec[0].doSomething(vec);
What happens if the push_back(...) in doSomething(...) causes the vector to expand? This means that vec[0] would be copied then deleted in the middle of executing its method. This would be no good.
Could someone explain what exactly happens here?
Does the program instantly crash? Does the method just try to operate on data that doesn't exist?
Does the method operate "orphaned" of its object until it runs into a problem like changing the object's state?
I'm interested in how a method call is related to the associated object.
Yes, it's bad. It's possible for your object to be copied (or moved in C++11 if the distinction is relevant to your code) while your are inside doSomething(). So after the push_back() returns, the this pointer may no longer point to the location of your object. For the specific case of vector::push_back(), it's possible that the memory pointed to by this has been freed and the data copied to a new array somewhere else. For other containers (list, for example) that leave their elements in place, this is (probably) not going to cause problems at all.
In practice, it's unlikely that your code is going to crash immediately. The most likely circumstance is a write to free memory and a silent corruption of the state of your F object. You can use tools like valgrind to detect this kind of behavior.
But basically you have the right idea: don't do this, it's not safe.
Could someone explain what exactly happens here?
Yes. If you access the object, after a push_back, resize or insert has reallocated the vector's contents, it's undefined behavior, meaning what actually happens is up to your compiler, your OS, what do some more stuff is and maybe a number of other factors like maybe phase of the moon, air humidity in some distant location,... you name it ;-)
In short, this is (indirectly via the std::vector implemenation) calling the destructor of the object itself, so the lifetime of the object has ended. Further, the memory previously occupied by the object has been released by the vector's allocator. Therefore the use the object's nonstatic members results in undefined behavior, because the this pointer passed to the function does not point to an object any more. You can however access/call static members of the class:
struct F
{
static int i;
static int foo();
double d;
void bar();
// some member variables
void doSomething(std::vector<F>& vec)
{
vec.push_back(F());
int n = foo(); //OK
i += n; //OK
std::cout << d << '\n'; //UB - will most likely crash with access violation
bar(); //UB - what actually happens depends on the
// implementation of bar
}
}

Trying to store an object in an array but then how to call that object's methods?

I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.

Calling a constructor to re-initialize object

is it possible to re-initialize an object of a class using its constructor?
Sort of. Given a class A:
A a;
...
a = A();
the last statement is not initialisation, it is assignment, but it probably does what you want.
Literally? Yes, by using placement new. But first you have to destruct the previously constructed object.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description.
It's possible, although it's a very bad idea. The reason why is that without calling the destructors on the existing object, you are going to leak resources.
With that major caveat, if you insist on doing it, you can use placement new.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
In C++11, you can do this:
#include <type_traits>
template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
static_assert(!std::has_virtual_destructor<T>::value, "Unsafe");
x.~T();
new (&x) T(std::forward<Args>(args)...);
}
This allows you to use Reconstruct passing arbitrary constructor parameters to any object. This can avoid having to maintain a bunch of Clear methods, and bugs that can easily go unnoticed if at some point the object changes, and the Clear method no longer matches the constructor.
The above will work fine in most contexts, but fail horribly if the reference is to a base within a derived object that has a virtual destructor. For this reason, the above implementation prevents use with objects that have a virtual destructor.
Short answer:
No. If part of your object's intended behavior is to be initialized several times, then the best way to implement this is through an accessible initialization method. The constructor of your class can simply defer to this method.
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Nitpicker corner:
Is there some incredibly evil way to call a constructor in C++ after an object is created? Almost certainly, this is C++ after all. But it's fundamentally evil and it's behavior is almost certainly not defined by the standard and should be avoided.
No, constructors are only called when the object is first created. Write a new method to do it instead.
Edit
I will not acknowledge placement new, because I don't want to have to get a pet raptor for work.
See this comic, but think of the topic on hand...
Yes you can cheat and use placement new.
Note: I do not advice this:
#include <new>
reInitAnA(A& value)
{
value.~A(); // destroy the old one first.
new (&value) A(); // Call the constructor
// uses placement new to construct the new object
// in the old values location.
}
I usually write the following in modern C++ :
SomeClass a;
...
a = decltype(a)();
It may be not the most effective way, as it effectively constructs another object of the same type of a and assigns it to a, but it works in most cases, you don't have to remember the type of a, and it adapts if the type changes.
Instead of destructing and reinitializing as suggested by some of the answers above, it's better to do an assignment like below. The code below is exception safe.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
May-be not what you have in mind, but since you didn't mention what it is for, I suppose one answer would be that you'd do it by controlling scope and program flow.
For example, you wouldn't write a game like this:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
Instead you'd strive for:
void play_level(level_number, level_data) {
Player player; //gets "re-initialized" at the beginning of each level using constructor
//code for level
}
void game() {
level_number = 1;
while (some_condition) {
play_level(level_number, level_data);
++level_number;
}
}
(Very rough outline to convey the idea, not meant to be remotely compilable.)
If you really must do this I strongly encourage creating a reset method for this:
class A
{
...
public:
reset() { *this= A() };
}
The above requires A to be copy and move assignable.
That is because the initial unoptimized version will copy from a temp. However copy elision may remove this step.
The behavior of A::reset() is always well defined. It replace the existing data in a valid A instance with a data from a new one. Of course any sub-class of A will still need to define its own version if you wanted its data re-initialized as well. However, failure to do so does not in and of itself invoke undefined or unspecified behavior. It simply means that only whatever memory A uses for its members will be reset. Even the involvement of virtual functions and/or virtual inheritance doesn't change this. Although the usual caveats of using such things apply.
Raw pointers will not be deleted by the above so they will need to be put into a std::shared_ptr or similar construct so the will self destruct when no longer needed.
While most answers are reinitializing an object in two steps; first, creating an initial object, and second creating another object and swapping it with the first one using placement new, this answer covers the case that you first create a pointer to an empty object and later allocate and construct it:
class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor
Yes , it is possible.
If you create a method that returns a new object.
#include "iostream"
class a // initialize class
a getNewA(a object){// Create function to return new a object
a new_object(/*Enter parameters for constructor method*/);
return new_object;
}

std::vector::clear() in constructor and destructor

I encounter many times with code where std::vector::clear() of class member of type std::vector is called in constructor and destructor.
I don't see why it's required:
constructor - the class member of type std::vector is empty by default, so no need to call clear().
destructor - the class member of type std::vector will be destroyed as part of standard destruction of object contnaining it. As part of vector destruction all value objects containied in it will be destroyed (if it heap allocated pointers to memory, they should be deleted "manually"), so again no need to call clear().
Do I miss something?
No, you're not missing anything. I suspect this is (harmless) voodoo programming, sort of like setting a pointer to null after freeing it, or randomly calling repaint/revalidate in GUI code. The programmer remembers that it helped with some sort of bug in the past and now adds it unnecessarily "just in case". Who knows, maybe it'll help. Voodoo.
From the sound of things, the people who wrote that code were the ones who missed something. The only time it would make sense to call clear() in a ctor or dtor would be in the middle of some other code. For example, a ctor might read in some data, process it, then read in more data. In such a case, it's probably faster to use a single container for the data as you read it in, and clear it each time, than to create a new container every iteration.
It's COMPLETELY unnessecary to clear the contents of an stl container in a constructor
It's unnessecary to clear the contents of an stl container in a destructor UNLESS the container contains a pointer. If the pointer has been created using new, it still needs to be deleted first. After that it still will not be nessecary to .clear the container.
Consider this :
#define BOOST_TEST_MODULE StlContainers
#define BOOST_LIB_DIAGNOSTIC
#include <boost/test/unit_test.hpp>
#include <boost/assign.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/assign/std/vector.hpp>
#include <vector>
using namespace boost::assign;
using namespace std;
const vector<int> my_ints_vector = list_of(0)(1)(1)(2)(3)(5)(8)(13)(21)(34);
struct ScopedStruct1
{
ScopedStruct1(const vector<int> & v) : m_v(v) {}
~ScopedStruct1() {}
private :
vector<int> m_v;
};
class A
{
public :
A(int i) : m_i(i) {}
~A() {}
private :
int m_i;
};
struct ScopedStruct2
{
ScopedStruct2() {}
~ScopedStruct2() { for(vector<A*>::iterator it = m_v.begin(); it != m_v.end(); ++it) delete *it; }
vector<A*> m_v;
};
struct ScopedStruct3
{
ScopedStruct3() {}
~ScopedStruct3() { /* no deletion */ }
vector<A*> m_v;
};
BOOST_AUTO_TEST_CASE(StlContainer_storing_something_simple)
{
ScopedStruct1 str(my_ints_vector);
}
BOOST_AUTO_TEST_CASE(StlContainer_storing_pointers_with_delete)
{
ScopedStruct2 str;
for(int i = 0; i < 10; i++)
str.m_v.push_back(new A(i));
}
BOOST_AUTO_TEST_CASE(StlContainer_storing_pointers_without_delete)
{
ScopedStruct3 str;
for(int i = 0; i < 10; i++)
str.m_v.push_back(new A(i));
}
Using boost's unit_test framework I've created 3 test cases. The unit_test framework is greate because it tracks memory leaks.
You'll notice that the 1st and 2nd test case don't generate memory leaks, but the 3rd case does because the vector's contents are not deleted.
Nope, you're right. Unless there is some additional business in the constructor (or constructor of the base classes) that require that, but the chances are very low...
Later edit
In case of destructor, one of the most common mistakes I saw is that some people assume that clear method will also call delete for vectors of pointers (vector), which, of course, it is not the case
The only case I can think of where it would be useful is where the order of destruction matters and the destructor wants to ensure that the objects in the vector are destroyed before something else.
Of course, it is better to structure code to not require that; however, it is a conceivable reason.
Despite what what said so far, there's at least one scenario when an explicit call to clear in the destructor might be necessary.
Imagine the situation when the object being destroyed has several member subobjects, which require some specific order of destruction, i.e. the subobjects somehow depend on each other, and an incorrect order of their destruction will lead to undesirable results. As you probably know, the order of member subobject destruction (as well as member initialization) is determined by the order of members' declararion in class definition. So, one way to achive the proper order of destruction is to arrange the member declarations accordingly. However, firstly, this is not a very good solution maintenance-wise. Secondly, the desired order of destruction might depend on some run-time conditions. Thirdly, the desired order of destruction might contradict the desired oreder of initialization. This all means that it might not be possible (or wise) to command the proper order of destruction by re-arranging the declarations.
A reasonable approach in this case might be to clean-up some critical member subobjects manually, by calling their clean methods or such, until the destruction order dependency "disappears". I would guess, that maybe the code that you saw was trying to resolve to ordering problem by calling clean on a strategically selected vector subobject.
As for calling clean in constructor... I have no idea why anyone would do something like that.
Of course one has to call clear() or resize(0) or the equivalent say (std::_Destroy_range(...) in the destructor before deallocating.
Deallocation is done via allocator::deallocate which does NOT run any destructors. It just frees the memory.
clear() is equivalent to resize(0) which runs destructors on the first size() things in the allocated buffer
NOT just allocated pointers, file handles, held mutexes, all other recoverable resources held by the object. The destructors MUST be run. Before instantiation the template doesn't know that the destructor is trivial. If the destructor is trivial, THEN its gets optimized out AFTER instantiation