Calling function when last instance of class is destructed / overwrited - c++

I'm trying to create a class wrapping fopen() / fclose() / f* methods. I want to use this method for other purposes, that's why I don't want to use smart pointers.
The problem is I don't know when to call fclose() or other 'end of life' functions. Destructor could be called but in the meantime FILE * was copied to another object for example by copy constructor.
I tried writing 'Reference Counter' class (that will be base class of all classes) but unfortunately I'm not able to call pure virtual methods from constructor / destructor.
This is what I've tried:
class ReferenceCounter
{
public:
ReferenceCounter()
{
ReferenceCount = new unsigned int(0);
AddRef();
}
ReferenceCounter(const ReferenceCounter & CopyFrom)
{
ReferenceCount = CopyFrom.ReferenceCount;
AddRef();
}
ReferenceCounter & operator = (const ReferenceCounter & AssignFrom)
{
RemoveRef();
ReferenceCount = AssignFrom.ReferenceCount;
AddRef();
return *this;
}
~ReferenceCounter()
{
RemoveRef();
}
virtual void OnInit() = 0;
virtual void OnDestruct() = 0;
private:
unsigned int * ReferenceCount;
void AddRef()
{
if(++*ReferenceCount == 1)
OnInit();
}
void RemoveRef()
{
if(--*ReferenceCount == 0)
{
OnDestruct();
delete ReferenceCount;
}
}
};
Maybe there is a way to 'overwrite' or 'overlay' one class over another?
Example:
class File
{
public:
File(std::string FileName)
{
F = fopen(FileName.c_str(), ...);
}
~File()
{
fclose(F);
}
private:
FILE * F;
};
int main()
{
File File1("a.txt");
auto File2 = File1;
//SegFault = fclose called twice for File1 and File2
}

There are two solutions here, which work in tandem.
First, don't allow assignment or copying of your "file handle" class.1
class File
{
// C++11 solution: use =delete
public:
File(File & const) = delete;
File & operator=(File & const) = delete;
// C++ < 11 solution: make them private and *don't implement them*:
private:
File(File & const);
File & operator=(File & const);
};
Second, consider only passing references to a single File object. (The compiler won't let you copy File objects anymore, so if you are doing this by accident you will get a compiler error -- this is good, because it will help you identify areas you need to fix.)
If it's too difficult to establish a single point of ownership, then consider instead passing instances using std::shared_ptr<File> which does exactly the kind of reference counting you are trying to implement -- the File will be deleted (and therefore its destructor called) when the last std::shared_ptr is itself destructed.
auto file = std::make_shared(new File{"a.txt"});
auto file2 = file;
// file.use_count() and file2.use_count() are now both 2.
//
// When file2 is destructed this will drop to 1; when file is destructed this will
// drop to 0, and the File object will be deleted.
1 Note that you could probably implement copying using dup(), though semantics for assignment may be a bit trickier -- should assignment close the existing handle and dup() the handle being assigned? If you do implement dup() functionality I would be more inclined to make it a member function instead so that its usage is explicit instead of happening automatically when you may not intend it to.

You can use a shared pointer with fclose as deleter:
#include <cstdio>
#include <memory>
#include <stdexcept>
class File
{
private:
typedef std::shared_ptr<FILE> shared_file;
public:
// You might consider const char*
File(const std::string& FileName, const std::string& Mode)
: F(std::fopen(FileName.c_str(), Mode.c_str()), fclose)
{
if( ! F.get()) {
throw std::runtime_error("File Open Failure");
}
}
private:
shared_file F;
};
int main()
{
File File1("/tmp/test.txt", "r");
auto File2 = File1;
}

Related

Why I'm getting "invalid use of incomplete type" error when I change raw pointer to unique_pointer?

I'm making some SDL2 wrappers in C++. Like this:
/* header file */
#include <SDL_mixer.h>
#include <memory>
class SDL2_Music {
public:
~SDL2_Music() { free(); }
bool loadMusic(const std::string& path);
bool play(int loops = -1);
// more methods
private:
void free();
Mix_Music* music_ = nullptr;
};
/* cpp file */
void SDL2_Music::free() {
if (music_ != nullptr) {
Mix_FreeMusic(music_);
music_ = nullptr;
}
}
bool SDL2_Music::loadMusic(const std::string& path) {
free();
music_ = Mix_LoadMUS(path.c_str()); // this returns a Mix_Music*
if (music_ == nullptr) {
ktp::logSDLError("Mix_LoadMUS");
return false;
}
return true;
}
// more stuff
This works fine, but I want to get rid of the raw pointer, so I can also get rid of the free() method and the dtor invoking it (yes, I'm reading about the rule of 0). So I made the following changes:
/* header file */
#include <SDL_mixer.h>
#include <memory>
class SDL2_Music {
public:
bool loadMusic(const std::string& path);
bool play(int loops = -1);
// more methods
private:
std::unique_ptr<Mix_Music> music_ = nullptr;
};
/* cpp file */
bool SDL2_Music::loadMusic(const std::string& path) {
music_ = std::make_unique<Mix_Music>(Mix_LoadMUS(path.c_str()));
if (music_ == nullptr) {
ktp::logSDLError("Mix_LoadMUS");
return false;
}
return true;
}
// more stuff
When I try to compile (GCC) I get:
"C:\Users\not_bjarne\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\unique_ptr.h|831|error:
invalid use of incomplete type 'struct _Mix_Music'"
And codeblocks points me to unique_ptr.h, which I obviously didn't tried to "fix".
It seems that Mix_Music is an incomplete type and the correct way to free a Mix_Music object is to call the Mix_FreeMusic function. You cannot dispose of it the way you would a C++ object, namely by using delete. delete would attempt to call the destructor (which cannot be done in this context, since the type is incomplete here) and would assume that the object was allocated by new and return the memory to the same pool where new got it from. The way SDL allocates the object is an implementation detail, so you must let SDL deallocate the object itself as well, to ensure it is done properly.
std::unique_ptr can be used for this purpose, but requires a custom deleter. The default deleter will call delete, which should not be done here. The error you are seeing is because delete p; is ill-formed (where p has type Mix_Music*) because of the incompleteness. You must ensure that the custom deleter calls Mix_FreeMusic. You can see how to use custom deleters here: How do I use a custom deleter with a std::unique_ptr member?

Compare the habits between move and smart pointer in C++?

In C++11/14, an object can be transfered by move or smark pointer.
(1) This is an example for move:
class MoveClass {
private:
int *tab_;
int alloc_;
void Reset() {
tab_ = nullptr;
alloc_ = 0;
}
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
MoveClass() : tab_(nullptr), alloc_(0) {}
~MoveClass() {
Release();
}
MoveClass(MoveClass && other) : tab_( other.tab_ ), alloc_( other.alloc_ ) {
other.Reset();
}
MoveClass & operator=(MoveClass && other) {
if (this == &other) return *this;
std::swap(tab_, other.tab_);
std::swap(alloc_, other.alloc_);
return *this;
}
void DoSomething() { /*...*/ }
};
When we use this movable MoveClass, we can write code like this :
int main() {
MoveClass a;
a.DoSomething(); // now a has some memory resource
MoveClass b = std::move(a); // move a to b
return 0;
}
Always write move-constructor/move-operator= is boring, use shared_ptr/unique_ptr some times have the same effect, just like java, reference/pointer everywhere.
(2) Here is the example:
class NoMoveClass {
private:
int *tab_;
int alloc_;
void Release() {
if (tab_) delete[] tab_;
tab_ = nullptr;
alloc_ = 0;
}
public:
NoMoveClass() : tab_(nullptr), alloc_(0) {}
~NoMoveClass() {
Release();
}
MoveClass(MoveClass && other) = delete;
MoveClass & operator=(MoveClass && other) = delete;
void DoSomething() { /*...*/ }
};
We can use it like this:
int main() {
std::shared_ptr<NoMoveClass> a(new NoMoveClass());
a->DoSomething();
std::shared_ptr<NoMoveClass> b = a; // also move a to b by copy pointer.
return 0;
}
Is it a good habit to always use the 2nd one?
Why many libraries, STL use the 1st one, not the 1st one ?
Always write move-constructor/move-operator= is boring
You almost never need to write your own move constructor/assignment, because (as you mentioned) C++ supplies you with a number of basic resource managers - smart pointers, containers, smart locks etc.
By relying on those in your class you enable default move operations and that results in minimal code size as well as proper semantics:
class MoveClass {
private:
std::vector<int> data;
public:
void DoSomething() { /*...*/ }
};
Now you can use your class as in (1) or as a member in other classes, you can be sure that it has move semantics and you did it in the minimal possible amount of code.
The point is one usually only needs to implement move operations for the most low-level classes which are probably covered already by STL, or if some weird specific behavior is needed - both cases should be really rare and not result in "Always writing move-constructor/move-operator=".
Also notice that while approach (1) is unnecessarily verbose, (2) is just unacceptable - you have a resource managing class that doesn't do its job and as a result you have to wrap it in smart pointers everywhere in your code, making it harder to understand and eventually resulting in even more code than (1)

QString in initializer list causes access violation. What goes wrong here?

I encountered an access-violation when using a QString in a initializer-list that I do not understand.
Here is a minimal example that reproduces the problem.
// file ClassA.h
#pragma once
#include <QString>
struct Parameter
{
QString stringPar;
};
class ClassA
{
QString m_string1;
public:
void function(Parameter pars);
};
Implementation of ClassA...
// file ClassA.cpp
#include "ClassA.h"
void ClassA::function(Parameter pars)
{
m_string1 = pars.stringPar; // last line called in my code when the crash happens
}
and main.cpp
// file main.cpp
#include "ClassA.h"
int main()
{
ClassA classA;
classA.function({ QString("jkjsdghdkjhgdjufgskhdbfgskzh") });
// when using this code the problem does not occur
//Parameter par = { QString("jkjsdghdkjhgdjufgskhdbfgskzh") };
//classA.function(par);
return 0;
}
The call stack at the time of the violation:
Qt5Cored.dll!QGenericAtomicOps<QAtomicOpsBySize<4> >::load<long>(const long & _q_value) Line 96
Qt5Cored.dll!QBasicAtomicInteger<int>::load() Line 142
Qt5Cored.dll!QtPrivate::RefCount::ref() Line 57
Qt5Cored.dll!QString::operator=(const QString & other) Line 1355
EducationalCode.exe!ClassA::function(Parameter pars) Line 6
EducationalCode.exe!main() Line 8
Something seems to go wrong with the copy assignment in ClassA::function() but I am not sure what it is.
When I change the signature of function to
function(const Parameter& pars);
it does not crash either.
Do you have any idea?
You should add a copy constructor:
struct Parameter
{
QString stringPar;
Parameter& Parameter(const Parameter& rhs)
{
if((void*)this == (void*)&rhs)
{
return *this;
}
this->stringPar = rhs.stringPar;
return *this;
}
};
A temp Parameter instance is created when you call ClassA::function() because of C++ passing arguments by value;
Something like this:
void ClassA::function(Parameter pars = QString("jkjsdghdkjhgdjufgskhdbfgskzh"))
{
m_string1 = pars.stringPar; // last line called in my code when the crash happens
}
If you don't write a copy constructor, compiler will synthesize a default copy constructor like this:
Parameter& Parameter(const Parameter& rhs)
{
memcpy(this, &rhs, sizeof(Parameter));
return *this;
}
I guess QString has pointer members, assuming it's name is ptr.
then pars.stringPar.ptr and QString("jkjsdghdkjhgdjufgskhdbfgskzh").stringPar.ptr will point to the same memory address.
Call function like this:
classA.function({ QString("jkjsdghdkjhgdjufgskhdbfgskzh") });
{ QString("jkjsdghdkjhgdjufgskhdbfgskzh") } object destroy before classA.function() return,
then memory pointed by {QString("jkjsdghdkjhgdjufgskhdbfgskzh")}.stringPar.ptr is freed,
and pars.stringPar.ptr point to invalid memory.
// when using this code the problem does not occur
//Parameter par1 = { QString("jkjsdghdkjhgdjufgskhdbfgskzh") };
//classA.function(par1)
//par1 destroy when main() function return, thus classA.function() does not crash.
See << Effective C++ >>
Item 11: Declare a copy constructor and an assignment operator for classes with dynamically allocated memory.
Effective C++, 2E
http://debian.fmi.uni-sofia.bg/~mrpaff/Effective%20C++/EC/EI11_FR.HTM

Memory Management with Command Pattern

So, I've got the following Command Pattern implementation, which is contained within a std::map<CString, IWrite*> commandMap:
class IWrite
{
protected:
CStdioFile* fileWriter;
public:
IWrite(CStdioFile* _fileWriter)
: fileWriter(_fileWriter)
{
}
virtual ~IWrite()
{
}
virtual BOOL exec() = 0;
};
class FloatWrite : public IWrite
{
private:
float input;
public:
FloatWrite(CStdioFile* _fileWriter, float _input)
: IWrite(_fileWriter), input(_input)
{
}
BOOL exec()
{
CString fieldvalue;
fieldvalue.Format("%f", input);
fileWriter->WriteString(fieldvalue);
return TRUE;
}
};
The issue I'm having is that my static analysis tool complains that fileWriter is not freed or zeroed in the destructor of IWrite. However, by adding a delete fileWriter in the destructor, I get a memory access error when I delete the Command Pattern object in the map before calling std::map.clear() as below:
// free map memory
for ( std::map<CString, IWrite*>::iterator mapItr = commandMap.begin();
mapItr != commandMap.end();
++mapItr)
{
delete mapItr->second;
}
commandMap.clear();
Am I approaching memory management incorrectly here? I have not done much work with STL maps, so I'm not familiar with an idiomatic approach.
EDIT: How I add elements to the map:
void FooClass::initCommandMap(const MSG_DATA_STRUCT * msgdata)
{
// Write a float, foo
commandMap[_T("foo")] = new FloatWrite(&fileWriter, msgdata->foo);
// Write an unsigned int, bar
commandMap[_T("bar")] = new UIntWrite(&fileWriter, msgdata->bar);
// etc...
}
This is called each time the user chooses to write out the data, so the fileWriter object used by the various exec()'s is current with the file selected by the user.
Note that CStdioFile fileWriter is a member variable of FooClass.
Why do you keep a pointer to fileWriter? From what I see, your Command object assumes that a writer should exist before the command can be used. It also shouldn't try to manage the writer object, since it can be shared by multiple command objects.
Try keeping a reference instead.
class IWrite
{
protected:
CStdioFile &fileWriter;
public:
IWrite(CStdioFile &_fileWriter)
: fileWriter(_fileWriter)
{
}
virtual ~IWrite()
{
}
virtual BOOL exec() = 0;
};

Print out the values stored in vars of different classes, that have the same ancestor

I have this class:
class CComputer {
public:
// constructor
CComputer(string name) {
this->name = name;
};
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component const & component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
string name;
string address;
list<Component> listOfComponents;
};
and then these classes:
// ancestor for other classes...It's really dummy yet, but I dunno what to add there
class Component {
public:
Component() {};
~Component() {};
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) {
this->mem = mem;
};
int mem;
};
Now I feed my CComputer class with some values:
CComputer c("test.com");
c . AddAddress("123.45.678.910") .
AddComponent(CCPU(8, 2400)) .
AddComponent(CCPU(8, 1200)).
AddComponent(CMemory(2000)).
AddComponent(CMemory(2000)));
And now I would like to print it out with all the info I've put in there (CCPU & CMemory details including)
but how to implement it, to be able to iterate through CComputer::listOfComponents and don't care if I acctually access CCPU or CMemory ? I can add it to that list, but I have really no idea, how to make it, to be able to access the variables of those components.
So the output should look like:
##### STARTING #####
CComputer:
name:test.com
address:123.45.678.910
CCPU:
cores:8,freq:2400
CCPU:
cores:8, freq:1200
CMemory:
mem:2000
CMemory:
mem:2000
###### FINISHED! #####
As others have mentioned, you need to implement a virtual function (e.g. virtual std::string ToString() const = 0;) in the base class that is inherited and overridden by each child class.
However, that isn’t enough. Your code exhibits slicing which happens when you copy your child class instances into the list: the list contains objects of type Component, not of the relevant child class.
What you need to do is store polymorphic instances. Values themselves are never polymorphic, you need to use (smart) pointers or references for this. References are out, however, since you cannot store them in a standard container (such as std::list). Using raw pointers is considered bad style nowadays, but judging from the naming conventions of your classes you don’t learn modern C++ in your class (sorry!).
Therefore, raw pointers is probably the way to go. Change your code accordingly:
Store a list of pointers:
list<Component*> listOfComponents;
Make the argument type of AddComponent a pointer instead of const&.
Call the function by passing a newed object, e.g.:
AddComponent(new CCPU(8, 2400))
Now your code leaks memory left, right and center. You need to implement a destructor to free the memory:
~CComputer() {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i)
delete *i;
}
But now your code violates the Rule of Three (read this article! It’s important, and it may be the most useful thing about C++ you’re going to learn in this programming class) and consequently you also need to implement the copy constructor and copy assignment operator. However, we can’t. Sorry. In order to implement copying for your class, you would have to implement another virtual function in your Component class, namely one that clones an object (virtual Component* Clone() const = 0;). Only then can we proceed.
Here’s a sample implementation in CCPU:
Component* Clone() const {
return new CCPU(cores, freq);
}
… this needs to be done in all classes deriving from Component, otherwise we cannot correctly copy an object of a type that derives from Component and is hidden behind a pointer.
And now we can implement copying in the CComputer class:
CComputer(CComputer const& other)
: name(name)
, address(addess) {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
}
CComputer& operator =(CComputer const& other) {
if (this == &other)
return *this;
name = other.name;
address = other.address;
listOfComponents.clear();
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
return *this;
}
This code is brittle, not thread-safe and error-prone and no competent C++ programmer would ever write this1. Real code would for instance use smart pointers instead – but as mentioned before I’m pretty sure that this would be beyond the scope of the class.
1 What does this make me now, I wonder?
Just add a virtual method to Class Component called e.g. toString(), which returns a string describing the component. Then you can iterate through all components and call toString() without worrying about exactly what each component is. If you do that, then for each computer you would be able to print out the values of all the components.
However, as pointed out in one of the comments, the example output you give in the question outputs the CCPU for all computers, then all the memory for all computers. To order the output like that, you'll need to add another virtual method to Component called e.g. getType() which returns an enum or integer that represents the type of the information. You can then have two for-next loops, one nested inside the other, where the outer loop iterates through all the types and the inner loop iterating through all the computers calling the toString() on all components which match the type specified in the outer for loop.
Here's something that implements this idea.
#include <iostream>
#include <string>
#include <list>
using namespace std;
int const TYPE_CCPU = 1;
int const TYPE_MEMORY = 2;
class Component {
public:
virtual int GetType() { return -1; }
virtual std::string ToString() const {
return "OOPS! Default `ToString` called";
}
};
class CComputer {
public:
typedef std::list<Component*>::iterator iter_t;
// constructor
CComputer(string name) {
this->name = name;
};
~CComputer() {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
delete *i;
}
}
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component *component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
void PrintType(int type) {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
if ((*i)->GetType() == type)
std::cout << (*i)->ToString() << '\n';
}
}
string name;
string address;
list<Component*> listOfComponents;
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int GetType() { return TYPE_CCPU; }
std::string ToString() const {
return "CCPU::ToString()";
}
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) { this->mem = mem; };
int GetType() { return TYPE_MEMORY; }
std::string ToString() const {
return "CMemory::ToString()";
}
int mem;
};
typedef std::list<CComputer*>::iterator iter_c;
int main() {
list<CComputer*> computerlist;
CComputer *c1 = new CComputer("test.com"), *c2 = new CComputer("test2.com");
c1->AddAddress("123.45.678.910").
AddComponent(new CCPU(8, 1200)).
AddComponent(new CMemory(2000));
computerlist.push_back(c1);
c2->AddAddress("987.65.432.10").
AddComponent(new CCPU(8, 2400)).
AddComponent(new CMemory(4000));
computerlist.push_back(c2);
for(int t=TYPE_CCPU; t<=TYPE_MEMORY; t++)
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
(*i)->PrintType(t);
}
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
delete (*i);
}
}
Implement ToString() in each of your classes. In .NET this is a standard even the "object" type implements.