How to trace MFC Serialize calls with Macros - c++

I got a MFC app that is writing a huge hierarichy of objects to disk.
To make sense of what is being written I thought of logging all the calls to archive << via stream insertion and .write method by replacing those with macros
#pragma once
#ifndef LOGMAGIC
#define LOGMAGIC
class LogTab
{
public:
static int LogIndentCount;
LogTab()
{
LogIndentCount++;
}
~LogTab()
{
LogIndentCount--;
}
};
#define ARINSERT(AR,OBJ) TRACE( "%*s %s\n", LogTab::LogIndentCount, #OBJ); AR << OBJ;
#define ARWRITE(AR,OBJ,SIZE) TRACE("%*s %s\n", LogTab::LogIndentCount, #OBJ); AR.write(OBJ, SIZE);
#endif
So I created above snippet of code and put it in stdafx.h but I'm getting the following error:
Error 1 error LNK2001: unresolved external symbol "public: static int
LogTab::LogIndentCount" (?LogIndentCount#LogTab##2HA)
What am I doing wrong?
Is there a better way to achieve what I am doing?

You have to define LogTab::LogIndentCount in any one of the .cpp files as,
#include"LogTab.h"
//...
int LogTab::LogIndentCount = 0;
[As a side note, if it's a multi threaded system which is using this class then you may think of making LogIndentCount synchronized (thread safe)]

A static variable must be explicitly initialized.

Related

error LNK2001 when using a static pointer to another class

I have a two classes. First (Spawn.cpp only prints the message that class was called):
// Spawn.h
#pragma once
#ifndef SPAWN_H_
#define SPAWN_H_
class Spawn {// const + destr only};
#endif /* SPAWN_H_ */
Second:
// Thread.h
#include "Spawn.h"
#pragma once
#ifndef THREAD_H_
#define THREAD_H_
class Thread
{
public:
Thread();
virtual ~Thread();
private:
void Initialise();
static int WindowThread(void *ptr);
static int ConsoleThread(void *ptr);
static Spawn * CreateSpawner();
static Spawn * pSpawner; // if the pointer is non-static, it can't be
// used within static function.
SDL_Thread * pConsoleThread;
};
Spawn * Thread::pSpawner = nullptr;
#endif /* THREAD_H_ */
The code itself:
// Thread.cpp
#include "stdafx.h"
#include "Thread.h"
Thread::Thread() { Initialise(); }
void Thread::Initialise() { // call of the threads here }
int Thread::WindowThread(void * ptr)
{
while (true)
{
// I want to access pointer pSpawner here
}
return 1;
}
int Thread::ConsoleThread(void * ptr)
{
// Main console loop
while (true)
{
/* Spawn handling */
if (CUI.INP == "spawn")
{
pSpawner = CreateSpawner(); // I am unable to access that
// pointer here as well
}
}
return 2;
}
Spawn * Thread::CreateSpawner()
{
// Singleton initialisation:
Spawn * m_pSPAWNER = new Spawn;
return m_pSPAWNER;
}
I am using the SDL external library to create two threads, these threads are static int functions, so it's possible to use only static pointer (if I use a standard pointer the error is that the pointer must be static), but the error I get using Visual studio 2015:
Error LNK2001 unresolved external symbol "private: static class Spawn * Thread::pSpawner"
Error LNK1120 1 unresolved externals
I have tried the suggestions done here, but no result (you can find declaration and definition in the Thread.h):
error LNK2001: unresolved external symbol public: static class
C++ vector issue - 'LNK2001: unresolved external symbol private: static...'
The answers from this question didn't helped (I will leave an update here when I will try all of the suggestions):
What is an undefined reference/unresolved external symbol error and how do I fix it?
This error message is pretty clear, you fail to define your global. It's better to define a global in a cpp file. Because with header he can be define each time you include the header.
// Thread.cpp
Spawn * Thread::pSpawner = nullptr;
It's useless to use #pragma once and #ifndef. Do only one of them.
#pragma once
By the way if you use #ifndef ALL must be inside the #if. You have included "Spawn.h" outside, its can produce an infinite loop of include.
"There is no advantage to use of both the #include guard idiom and #pragma once in the same file."

Unresolved external symbol when putting definition in CPP file

For the life of me I cannot figure out what is causing this... I keep getting unresolved external symbol error. However, if I put an empty definition in the header file it compiles correctly.
WINMAIN.CPP
#include "FILE_XXX.H"
int WINMAIN WinMain(...)
{
EnableOpenTest(); // call like this
return 0;
}
FILE_WORKS_CORRECTLY.H
#ifndef _FILE_WORKS_CORRECTLY_
#define _FILE_WORKS_CORRECTLY_
void EnableOpenTest() { }
#endif
However, when I do something like this (correctly), it does not work and I get a compile-time error.
FILE_DOES_NOT_WORK_CORRECTLY.H
#ifndef _FILE_DOES_NOT_WORK_CORRECTLY_
#define _FILE_DOES_NOT_WORK_CORRECTLY_
void EnableOpenTest();
#endif
FILE_DOES_NOT_WORK_CORRECTLY.CPP
#include "FILE_DOES_NOT_WORK_CORRECTLY.H"
void EnableOpenTest() { /* do work here */ }
UPDATE:
Upon further investigation, I found the issue has to do with me having multiple projects in the same solution. I then try to reference a function in one project from another project. Obviously I'm doing this incorrectly.
The only mistake i see is that in the cpp file you need to include the return type as well. It should be
void EnableOpenTest()
{
//Enter Code Here
}
Inside of FILE_DOES_NOT_WORK_CORRECTLY.CPP:
EnableOpenTest(){ /* do work here */ }
must be
void EnableOpenTest(){ /* do work here */ }
Looks like your compiler sets the missing return type to int instead of yelling at you with a error message.
You should turn on compiler warnings, it would allow you to notice such errors very quickly.
Also, inside of FILE_WORKS_CORRECTLY.H you have another error:
void EnableOpenTest() { }
must be
inline void EnableOpenTest() { }
Otherwise it will trigger a error message if this header is included twice (i.e. in more that one .cpp file).
Solved it!
Additional projects needed to be static library (main project .exe)
Added References of library projects to main project
Obviously the file structure caused a lot of these issues.

C++ error LNK2001 issue

I am fairly new to cpp but have been in c# for a while. I am trying to run a simple console application but I receive this LNK2001 error message.
I have the main.cpp, and have added another class, Zeus, with files, Zeus.h and Zeus.cpp.
Here is the main.cpp:
#include "Zeus.h"
#include <iostream>
int main()
{
Zeus::tick = 25.0;
using std::cout;
cout << "nothing";
}
Here is the Zeus.h:
static class Zeus
{
public:
static void testing(void);
public:
static double tick;
};
And here is the Zeus.cpp:
void Zeus::testing(void)
{
//Doesnt get this far
//But eventually something like
// cout << "test " << Zeus::tick;
}
And here is the error message:
Error 20 error LNK2001: unresolved external symbol "public: static double Zeus::tick"
Thanks,
You need to define Zeus::tick, typically you would to that in the in the Zeus.cpp file. You have only declared it.
double Zeus::tick = 0.0;
Also, there is no static class in C++.
As an aside, free functions can be put in namespaces, as opposed to being static functions of classes. This is the preferred way in C++, unless there are strong reasons for the function to be static.
namespace Dionysus {
void testing();
}
As the error message says: there's no definition of Zeus::tick. Add this to Zeus.cpp:
double Zeus::tick;
Oh, and in Zeus.h remove the static from
static class Zeus
In the main() function you have, what do you mean by a statement Zeus::tick = 25.0;?
Zeus is a class. So to access the individual elements of it you need to create its instance. Its just like a structure where you first create its instance to access its individual elements.
Try the following:
int main() {
Zeus myobject;
myobject.tick = 25.0;
/* Rest of the definition */
}

C++ Windows Plugins - Passing Classes

I am working on a plugin system in C++ whereby a C++ executable loads a dll and runs plugin_start(someclass&) via GetProcAddress.
I fully understand how to pass function pointers to the dll, and visa versa, and how the dll may use anything defined in a header file, but I would like the dll to be able to use someclass where someclass is declared in someclass.h BUT DEFINED in someclass.cpp.
The catch is, someclass is compiled into the calling executable which means when the dll tries to call a function it gets a linker error. I even understand why this is, what I don't understand is how to achieve what I want.
I imagine I can pass a pointer to the object, and a pointer to the function ie someclass* somefunction* and then call it as someclass->*somefunction() but this means I would have to pass a pointer to every function in every class.
Is there an easier way to do this, or should I stick to C-style functions and function pointers alone and forget trying to pass entire classes between the two?
Thanks,
Ben
#ifndef EVENTREGISTRAR_H
#define EVENTREGISTRAR_H
#include <vector>
typedef void (__stdcall *error_callback_t)(const char *error);
class EventRegistrar
{
public:
void OnError(error_callback_t fn);
void FireError(const char *error);
private:
std::vector<error_callback_t> errors;
};
#endif
-- Cpp
#include "PluginLoader.h"
void EventRegistrar::OnError(error_callback_t fn)
{
this->errors.push_back(fn);
}
void EventRegistrar::FireError(const char *error)
{
for (std::vector<error_callback_t>::iterator it = this->errors.begin();
it != this->errors.end(); ++it)
{
(*it)(error);
}
}
-- DLL
#include "../plugin.h"
#include <stdio.h>
void __stdcall error(const char *error) { printf("Error: %s\n",error); }
extern "C" int __stdcall plugin_start(plugin_start_data& data)
{
error_callback_t fn = error;
data.events.OnError(fn);
return LOAD_SUCCESS;
}
--Error
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall EventRegistrar::OnError(void (__stdcall*)(char const *))" (?OnError#EventRegistrar##QAEXP6GXPBD#Z#Z) D:\Files\C++ Workspace\BLib\BLib\Example Plugin\main.obj Example Plugin
I did something like this a long time ago. I simply used a straight C interface to keep things simple.
There may be a better way but I think passing a pointer to the object is your best and most straight-forward approach.

LNK2001 using a std::vector of a custom struct

I want to have some data cache which contains some objects which I can update over an UpdateCache function. However, I'm getting problems with a LNK2001 followed by a LNK1120.
HeaderFile.h
#ifndef headerfile_included
#define headerfile_included
#include <vector>
struct MyObject {
unsigned int A;
unsigned int B;
};
class MyClass {
private:
static std::vector<MyObject> myObjectCache;
public:
static void UpdateCache ();
};
#endif
CodeFile.cpp
#include "HeaderFile.h"
void MyClass::UpdateCache () {
myObjectCache.clear();
/* Repopulate cache with new data */
}
The error message I get from the linked is
error LNK2001: unresolved external symbol ""private: static class std::vector > MyClass::myObjectCache" (?myObjectCache#MyClass##0V?$vector#UMyObject##V?$allocator#UMyObject###std###std##A)".
fatal error LNK1120: 1 unresolved externals
My opinion is that it is some problem with the partitioning into the header file and the code file as I have had similar problems with improper partitioning. If it is again such a problem, it would be nice if you could post some rule on what to put into the header file and what into the code file since it's pretty confusing.
You need to add this to a cpp file:
std::vector<MyObject> MyClass::myObjectCache;
The reason is that as a static exists without a class ever being instantiated it needs to exist whether an instance of the class is instantiated or not. The line above creates the instance of the static and thus it exists whether or not you ever create an instance of the class itself.
Since your vector is static, essentially a global entity as far as the compiler is concerned, you need to be sure to give it a home in a compilation unit. That's why you have to do what #Goz says and do
std::vector<MyObject> MyClass::myObjectCache;