I am trying to Overload operator <<
so the Error can be printed using cout
. I need to print the c-string
pointed by m_messag
e. Can anyone help me solve this ?
My Error.h
header :
ifndef ICT_ERROR_H_
#define ICT_ERROR_H_
#include <iostream>
namespace ict {
class Error {
char* m_message;
public:
// constructors
Error();
Error(const char* errorMessage);
// destructor
virtual ~Error();
// deleted constructor and operator=
Error(const Error& em) = delete;
Error& operator=(const Error& em) = delete;
// operator= for c-style strings
void operator=(const char* errorMessage);
// methods
void clear();
bool isClear()const;
void message(const char* value);
// cast overloads
operator const char*() const;
operator bool()const;
};
// operator << overload prototype for cout
std::ostream& operator<<(std::ostream& os, const Error& E);
}
#endif
Error.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include "Error.h"
namespace ict{
Error::Error()
{
m_message = nullptr;
}
Error::Error(const char * errorMessage)
{
m_message = nullptr;
message(errorMessage);
}
Error::~Error()
{
delete[] m_message;
}
void Error::operator=(const char * errorMessage)
{
clear();
message(errorMessage);
}
void Error::clear()
{
delete[] m_message;
m_message = nullptr;
}
bool Error::isClear() const
{
bool status = false;
if (m_message==nullptr) {
status = true;
}
return status;
}
void Error::message(const char * value)
{
delete[] m_message;
m_message = new char[strlen(value)+1];
strcpy(m_message,value);
}
Error::operator const char*() const
{
return m_message;
}
Error::operator bool() const
{
return isClear();
}
***std::ostream& operator<<(std::ostream& os, const Error& E) {
if (E.isClear()) {
}
return os << E.operator const char *();
}***
}
Main.cpp
int main(){
Error T("Testing Error Message");
cout << T << endl ;
}
When i execute it , it gives the correct output but it crashes with the following error :
Exception thrown: read access violation.
_First was nullptr.
Debugger :
static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
{ // find length of null-terminated string
//next statement to be executed ---> return (*_First == 0 ? 0
: _CSTD strlen(_First));
}
I copied all your code into one file to find out what's wrong. The test in operator << ()
(whether error is clear) was missing. However, in your test this branch should not become active.
#include <iostream>
#include <cstring>
#define _CRT_SECURE_NO_WARNINGS
namespace ict {
class Error {
char* m_message;
public:
// constructors
Error();
Error(const char* errorMessage);
// destructor
virtual ~Error();
// deleted constructor and operator=
Error(const Error& em) = delete;
Error& operator=(const Error& em) = delete;
// operator= for c-style strings
void operator=(const char* errorMessage);
// methods
void clear();
bool isClear()const;
void message(const char* value);
// cast overloads
operator const char*() const;
operator bool()const;
};
// operator << overload prototype for cout
std::ostream& operator<<(std::ostream& os, const Error& E);
} // namespace ict
namespace ict{
Error::Error()
{
m_message = nullptr;
}
Error::Error(const char * errorMessage)
{
m_message = nullptr;
message(errorMessage);
}
Error::~Error()
{
delete[] m_message;
}
void Error::operator=(const char * errorMessage)
{
clear();
message(errorMessage);
}
void Error::clear()
{
delete[] m_message;
m_message = nullptr;
}
bool Error::isClear() const
{
bool status = false;
if (m_message==nullptr) {
status = true;
}
return status;
}
void Error::message(const char * value)
{
delete[] m_message;
m_message = new char[strlen(value)+1];
strcpy(m_message,value);
}
Error::operator const char*() const
{
return m_message;
}
Error::operator bool() const
{
return isClear();
}
std::ostream& operator<<(std::ostream& os, const Error& E) {
if (E.isClear()) return os;
return os << E.operator const char *();
}
} // namespace ict
int main(){
ict::Error T("Testing Error Message");
std::cout << T << std::endl;
return 0;
}
I compiled it with VS2013 on Windows 10 (64 bit) and started the debugger.
As you see I added return 0;
in main()
. Actually, it is allowed to leave it out but it's a good point to place a breakpoint. Thus, I got the following output:
Testing Error Message
Hmm. So, where is the issue you described? I don't like the design (a matter of taste) but it works as expected. I looked for potential leaks or bugs:
If Error::message()
is called with a nullptr
then strlen()
(and strcpy()
) will probably crash. If you document the API with something like "Do not call Error::message()
with a nullptr
." I would find this sufficient.
Either you didn't provide all information or you didn't test this sample in your debugger.
What you really need to know is how your debugger works:
Clicking in the gray bar left of text editor(s) places a break point. In debug mode the execution will stop (automatically) at break points. The respective source code is made visible (raising the editor tab and scrolling the text appropriately.
F9 ... toggle break point in current line
F10 ... step over (single step - execute functions as one statement)
F11 ... step in (single step - enter functions)
Shift F11 ... step out (execute code until return from current function)
F5 ... execute code (continuously until break point)
All these commands are available in menu bar and on toolbar. However, debugging is more convenient remembering the above keys.
Also, become familiar with Local, Watch, and Call Stack.