2

I am puzzled by a NULL value for "this" in one of my native C++ classes.

I declare the class in stdafx.h like so:

extern Filing* Files;

Then implement it in stdafx.cpp like so:

Filing* Files = new Filing();

The debugger chokes on this method, and throws a "Write access violation": Message also says: "this was nullptr".

void Filing::Startup()
{
this->ExePath = this->GetPathToExe(); //Throws right here
this->LogDirectoryPath = this->GetLogDirectoryPath();
CreateDirectory(LogDirectoryPath->c_str(), NULL);
}

How is this possible? How do I fix this? Full "Filing" header and definition below.

Filing.h:

#pragma once

#include <Windows.h>
#include <sstream>

using namespace std;

class Filing
{
  public:
     Filing();
     ~Filing();

/// <summary>
/// The path to this exe.
/// </summary>
     wstring* ExePath;

/// <summary>
/// The path to the log folder that exists or will be created.
/// </summary>
    wstring* LogDirectoryPath;

/// <summary>
/// Kicks off some startup logic.
/// </summary>
    void Startup();

/// <summary>
/// Determines if the specified directory exists.
/// </summary>
/// <param name="Path"></param>
/// <returns></returns>
    bool DoesDirectoryExist(string* Path);

  private:

/// <summary>
/// Returns the directory from which this executable is running from.
/// </summary>
    wstring* GetPathToExe();

/// <summary>
/// Gets the path to the log directory.
/// </summary>
/// <returns></returns>
    wstring* GetLogDirectoryPath();
};

Filing.cpp:

#include "stdafx.h"
#include "Filing.h"

Filing::Filing()
{
   this->Startup();
}

Filing::~Filing()
{
   delete this->ExePath;
   delete this->LogDirectoryPath;
}

void Filing::Startup()
{
   this->ExePath = this->GetPathToExe();
   this->LogDirectoryPath = this->GetLogDirectoryPath();
   CreateDirectory(LogDirectoryPath->c_str(), NULL);
}

bool Filing::DoesDirectoryExist(string* Path)
{
   DWORD ftyp = GetFileAttributesA(Path->c_str());

   if (ftyp == INVALID_FILE_ATTRIBUTES)
   {
     Console->WriteLine("Invalid path!");
     return false;  //something is wrong with your path!
   }

   if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
   {
      return true;   // this is a directory!
   }

   return false;    // this is not a directory!
}

wstring* Filing::GetPathToExe()
{
   #ifdef UNICODE
   TCHAR ownPth[260];
   #else
   char ownPth[MAX_Path];
   #endif // UNICODE

   // Will contain exe path
   HMODULE hModule = GetModuleHandle(NULL);
   if (hModule != NULL)
   {
      // When passing NULL to GetModuleHandle, it returns handle of exe itself
      GetModuleFileName(hModule, ownPth, (sizeof(ownPth)));
      return new wstring(ownPth);
   }
   else
   {
      throw new exception("Error! NullPointerException!");
   }
}

wstring* Filing::GetLogDirectoryPath()
{
   //if (this == nullptr)
   //{
   //   int i = 0;
   //}

   wstring *directory;
   const size_t last_slash_idx = ExePath->rfind('\\');
   if (string::npos != last_slash_idx)
   {
      directory = new wstring(ExePath->substr(0, last_slash_idx));
      directory->append(L"\\Logs");
   }
   else
   {
      throw new exception("Error! Directory not found from path!");
   }
   return directory;
}

Things I have tried so far:

Clean and Rebuild.

Initializing Filing.

EDIT:

I have seen some comments about not using stdafx.h and stdafx.cpp for what I am using it for. I am using them for global variables/classes right now. How could I define them elsewhere and still be global?

EDIT2:

Traced the error all the way back to a little GetTime() function.

const char* Writer::GetTime()
{
    string* Formatted = new string("[");
    time_t rawtime;
    tm* timeinfo;
    char buffer[80];
    time(&rawtime);
    timeinfo = std::localtime(&rawtime);

    strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", timeinfo);
    Formatted->append(buffer);
    Formatted->append("]: ");

    const char* Ret = Formatted->c_str();

    delete Formatted;
    delete timeinfo;//Errors here SOMETIMES. Any ideas?
    return Ret;
}

1 Answers1

3

Here's an example of a program that may result in you seeing this set to be a NULL pointer. (I say may because per the C++ language specification, this program invokes undefined behavior, so technically the compiler is free to crash or output an executable for PacMan or whatever else it wants to do in response to this source code... but in many compiler implementations, a commonly-observed behavior is a NULL this-pointer. Ahem):

#include <stdio.h>

class Foo
{
public:
   Foo() {/* empty*/}

   void bar() {printf("this=%p\n", this);}
};

int main(int, char **)
{
   Foo * f = NULL;
   f->bar();  // undefined behavior here: calling a method on a NULL object!
   return 0;
}

When I run this program, I get this output:

$ ./a.out 
this=0x0

Needless to say, you shouldn't do this in any real program.

As for your own code, the most likely explanation is that you are calling the Startup() method on a NULL pointer. The solution would be to track down all the locations where you call Startup(), and make sure that the pointer they call Startup() on is non-NULL (and pointing to a valid object) before calling any methods on it.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234