I am writting a parser, and when casting I am having trouble distingushing between a normal class type, and an array class type.
Having something similar to the following would help me a lot:
if (expression causes segmentation fault)
do sth
else
do sth else
If not this, then, what would be a good way to distinguish two classes from each other?
if (base->type->GetType() != "") {
char *key = strcpy(key, base->type->GetType().c_str());
Node *node = (stack->front).Lookup(key);
if (node != NULL) {
theclass = dynamic_cast<ClassDeclaration *>(node);
}
if (!base->GetType()->IsEquivalentTo(GetType()))
errReport.FieldNotFoundInBase(field, type);*/
if (theclass->id->name){ // segfault happens here.
The variable theclass, is sometimes initialized as an actual class, sometimes as an array. the seg faults happens in the line if (theclass->id->name) { when there is an array class instead of an actual class, since the array class doesn't really have a name field. I don't really have a way of telling in which type theclass variable is being initialized.
If node is an instance of ClassDeclaration, then dynamic_cast<ClassDeclaration *>(node) will return node "converted" to a ClassDeclaration* [1]. Otherwise, it returns 0 (or, more accurately, nullptr cast to ClassDeclaration*.
You don't check for the nullptr value. Dereferencing a nullptr will almost certainly segfault (although technically it's UB, so it could do anything.)
Now, it's possible that something more esoteric is going on and the segfault isn't happening because the dynamic_cast failed and returned nullptr and you then proceeded to dereference that value. It's possible. We'd all know for certain if you checked the return value.
Note 1: It's possible for dynamic_cast to change the pointer value, for example if the cast-to type is not the first base type of a multiply-inherited object. So I probably shouldn't have put scare-quotes around the word "converted".
Related
I'm starting to write a rather large Qt application and instead of using raw pointers I want to use smart pointers, as well as Qt's own guarded pointer called QPointer.
With both standard library smart pointers and Qt's pointers the application crashes when a NULL pointer is dereferenced.
My idea was that I could add a custom overload to the dereference operators * and -> of these pointer types that check if the pointer is NULL.
Below is a short example that works fine so far. If a NULL pointer was dereferenced, a temporary dummy object would be created so that the application does not crash. How this dummy object would be processed might not be always correct, but at least there would be no crash and I could even react on this and show a warning or write it to a log file.
template <class T>
class Ptr : public std::shared_ptr<T> {
private:
T * m_temp;
public:
Ptr<T>(T * ptr) : std::shared_ptr<T>(ptr), m_temp(NULL) {}
~Ptr() {
if (m_temp) {
delete m_temp;
}
}
T * operator->() {
if (!std::shared_ptr<T>::get()) {
if (m_temp) {
delete m_temp;
}
m_temp = new T();
return m_temp;
} else {
return std::shared_ptr<T>::get();
}
}
T & operator*() {
return *operator->();
}
};
Of course I'll be doing NULL checks and try to eliminate the source of NULL pointers as much as possible, but for the rare case that it I forget a NULL check and the exception occurs, could this be a good way of handling it? Or is this a bad idea?
I would say this is a bad idea for a few reasons:
You cannot derive from standard library types. It may work until you change something benign in your code and then it breaks. There are various things you can do to make this more acceptable, but the easiest thing is to just not do this.
There are more ways to create a shared_ptr than just a constructor call. Duplicating the pointer value in your m_temp variable is likely just to lead things to be out of sync and cause more problems. By the time you cover all the bases, you will have probably re-implemented the whole shared_ptr class.
m_temp = new T(); seems like a frankly crazy thing to do if the old pointer is null. What about all the state stored in the object that was previously null? What about constructor parameters? Any initialization for the pointer? Sure, you could maybe handle all of these, but by that point you might as well handle the nullptr check elsewhere where things will be clearer.
You don't want to hide values being nullptr. If you have code using a pointer, it should care about the value of that pointer. If it is null and that is unexpected, then something further up the chain likely went wrong and you should be handling that appropriately (exceptions, error codes, logging, etc.). Silently allocating a new pointer will just hide the original source of the error. Whenever there is something wrong in a program, you want to stop or address the problem as close to the source as possible - it makes debugging the problem simpler.
A side note, if you are confident that your pointers are not null and don't want to have to deal with nullptr in a block of code, you may be able to use references instead. For example:
void fun1(MyObject* obj) {}
void fun2(MyObject& obj) {}
In fun1, the code might need to check for nullptr to be well written. In fun2, there is no need to check for nullptr because if someone converts a nullptr to a reference they have already broken the rules. fun2 pushes any responsibility for checking the pointer value higher up the stack. This can be good in some cases (just don't try and store the reference for later). Note that you can use operator * on a shared_ptr/unique_ptr to get a reference directly.
I wanted to know if I can check a reference against being invalid. I believe I can, but I'm not sure. Related to this, I would also like to know if in the following case I am "dereferencing" the pointer:
struct Texture { int width; };
void useTexture(Texture& texture)
{
int a = texture.width;
//Exception thrown: read access violation.
texture was nullptr.
// When I hover the mouse over the argument it says "struct at null"
}
int main()
{
Texture* obj = nullptr;
useTexture(*obj); // This is using the dereference operator,
// but no exception is thrown here.
}
The exception only occurs in the useTexture() function. In this case when passing the *obj argument to the function, it's not reading data from this location, it's just giving the address to the reference, I assume in no different way than would happen when passing a pointer. So even if I used the dereference operator did it actually dereference the pointer? I don't think so.
Also I would like to know if there's a way to check in the useTexture() function if the reference is valid. In the debugger when I hover over the argument it says the struct is at null, and when it throws the exception it says that texture is nullptr. I'm assuming it's saying nullptr because its address is 0x00, because texture isn't a pointer at all, but a reference.
Likewise, if I do:
Texture* obj = (Texture*)0x80;
useTexture(*obj);
Instead of saying "struct at null" it says it can't read the data, and when throwing the exception it says "invalid memory access at 0x80". This I understand.
What I wanted to do was to have a safety check in the function that checks if its valid. Remembering that people say references can't be null, I thought I'd have to change the function to take a pointer, and I could check against a pointer value, like nullptr. But from what I've seen references also have addresses, and can be null. Is there a way to check if the reference is valid without changing it to a pointer argument? I guess the dereference question is a separate question, but didn't want to make two questions.
Edit: I was just testing, and thought I could do something like:
if ((Texture*)&texture == nullptr) return;
Instead of checking for nullptr at the call site.
Doing something like this:
A * a = nullptr;
A b = * a;
Is undefined in C++. It's also undefined even if you don't create the named variable, because the compiler may decide to create a nameless temporary by dereferencing a. So this statement:
* a;
is also undefined.
If a C++ class member function requires a pointer to an object as an argument, is it considered bad practice to pass by reference?
The following code, for example, will work, however without the pass by reference it becomes a dangerous code, and will lead to catastrophic errors at runtime.
class ClassA
{
public:
void SetPointer(const ClassB& classb) // Remove 1 ampersand and serious errors will occur
{
if(ptr_to_classb == nullptr) // Initialized to nullptr in constructor
ptr_to_classb = &classb;
else
throw(...); // Throw some error
}
private:
ClassB* ptr_to_classb;
}
Consider if passing by value, and a copy of the argument was made, that this would be disastrous when dereferencing at a later time.
The alternative is this:
class ClassA
{
public:
void SetPointer(const ClassB* const classb)
{
if(ptr_to_classb == nullptr) // Initialized to nullptr in constructor
ptr_to_classb = (ClassB*)(classb);
else
throw(...); // Throw some error
}
private:
ClassB* ptr_to_classb;
}
I like consistency, to defaulted to the first type, however I suspect that the second form is considered to be better practice. Is this the case?
Well, both approaches are correct and fine but in your case it will be probably better to go with pointers, since a reference variable can only be assigned a value at initialization unlike pointers. With the same pointer you could later pass a different class object.
My view is that if passing a null argument to the method is a valid thing to do (i.e. the logic that the method executes would be valid with a null pointer), then use a pointer. If the argument should never be null then use a reference.
In your case this depends on whether it is valid for ClassA::ptr_to_classb to be null. Since you throw if ptr_to_classb is already set (meaning you don't ever want to change what it points to) you might even want to conside storing a reference instead and passing that in the constructor of ClassA, getting rid of ClassA::SetPointer.
There are some other opinions on reference vs pointer here as well.
Your method just sets a field of your object, so it seems you want to use the type of the field (which is pointer, not reference). You wrote
I like consistency, to defaulted to the first type
which, I guess, refers to the rule "use references when possible; use pointers oterwise". I think your case is an exception from this rule, because the declaration
void do_stuff(ClassA& object)
usually means "do stuff on the object, and forget about it", and your case is different.
It's not clear for me how can i do that in C++. In Objective-C I can check a object in this way
if (myValue != [NSNull null]) { … }
myValue is compared with a null object (returned by class method), so this works great , if object has a value, even nil, if statement will return true.
So question is how to test correctly for a null pointer value, i did this way
if (myValue != NULL)
{
qDebug() << "It is not null";
}
but it is not working.
In C++ there's really no concept of null value, only null pointers. You can't compare something that isn't a pointer to NULL.
A pointer in C++ essentially contains an address to some memory location where you object or data is stored. In this case, a "NULL Pointer" is just an empty memory address. This is represented as a zero value. So to check it, you would write something like this:
SomeClass *someClassPointer = // ... call some method to get pointer
// Check for null pointer
if (someClassPointer == 0)
{
// Pointer is null
}
This can be simplified by doing this:
if (someClassPointer)
{
// For checking that the pointer is not null
}
if (!someClassPointer)
{
// For checking that a pointer is null
}
Short answer: it depends.
Longer answer: First of all you can not compare a reference (if the type of myValue is something like T&) nor stack allocated objects (if myValue is just T) for null - these types are always allocated and not null (unless you screw up your stack or do other bad stuff - but you won't check for these cases, because than you will have bigger problems).
The only types you can check for null are pointers (myValue is something of type T*). For those types:
if you use C++98, you can check against 0. NULL is usually just a macro (#define NULL 0).
if you use the new C++11 there is a new nullptr keyword and you should check against this one.
Since 0 evaluates to false and anything else to true, you can also just use the pointer like a normal bool. A nullptr is of type nullptr_t and has operator bool() implemented - so you also can this one like you would use a bool.
In general: in C++98 the lack of nullptr is a source of errors, so if you can use C++11, ALWAYS use nullptr - never use NULL or 0 (int is just the wrong type to assign to a pointer or to compare with a pointer - if you have overladed methods you will run into problems since the compiler would use a method with an int parameter instead of a pointer type if it is suitable).
Let's assume you have two functions:
void foo(int a);
void foo(void *);
If you now call
foo(NULL);
the first function will get called (what probably is not what you want. So in C++11 you would write:
foo(nullptr);
while in C++98 you would have to write:
foo((void *)0);
This is one reason why the lack of null is/was a big issue before C++98. If you want to have something similar than in Objective-C, you could write the following function (for C++98):
template<typename T>
inline bool isNull(const T *obj) {
return obj == ((const T *) 0);
}
// to use it:
if (isNull(myType)) { //myType is a pointer to something
// some code
}
Although I never saw that one used in practice.
I hope this answer helps in understanding the concept in C++.
If i'm right, you want to check for null pointers. This is actually very easy in C++
Foo *pInstanc = new Foo;
if(pInstance)
{
//do something with pInstance
}
Here's what I have done:
I've got a simple class:
class Person{
public:
Person();
}
And in my main:
int main() {
Person myPer = NULL;
}
This is impossible since C++ does not allow that, however:
int main() {
Person* perPtr = NULL;
Person myPer = *perPtr; // corrected, it was &perPtr(typo error) before answers
}
This compiles fine and as I see I did able to have a NULL object. So isn't it violating the rule that only pointers can be null in C++? Or is there such a rule in C++?
2nd one is after I wrote this code, I added a if statement checking whether myPer is NULL or not but that gave me error. So does it show that C++ does not really like the NULL object idea no matter what you do to make objects NULL...
Objects cannot be null, only pointers can. Your code is incorrect and does not compile, since its trying to initialize a Person from a pointer to a pointer to Person. If you were to change your code to
Person* perPtr = NULL;
Person myPer = *perPtr;
then it would be trying to initialize a Person out of a dereferenced null pointer to a Person, which is undefined behavior (and most likely a crash).
If you need to use the idioms where an object could be in a NULL state, you could use Boost.Optional:
boost::optional< Person > myPer = boost::none;
if( myPer )
{
myPer->do_something();
}
It's a generalization of what is usually done with pointers, except it does not use dynamic allocation.
This is undefined behaviour. C++ references cannot be legally set to NULL. If you want a "nullable reference", use a pointer.
This is called undefined behavior. Unexpected results may happen when you attempt to dereference NULL or get the address of NULL.
References are basically syntactically nicer way of saying pointers.
You can make a class that has "NULL" state.
E.g. a class that owns something else, such as a file handle or a window handle or anything else, such that it can be empty or not.
You can see this with any string class or with any container class.
if (x.empty()) ...
But the concept of "is null" is limited to pointers and smart pointers (or any class that you override to support such use cases.
You can not have a NULL object in C++. Your first attempt is trying to set an object equal to a pointer, and thus fails.
You can have a NULL pointer, and references are simply pointers with slightly different syntax.
You can de-reference a NULL pointer (as in the compiler will let you), but that's undefined behavior. If you're lucky, dereferencing NULL will crash, so you know what's going on.
I would not say the following is impossible since C++ does not allow it:
int main() {
Person myPer = NULL;
}
It is possible, and C++ does allow it. It all depends on how you've defined the classPerson. For example, if the class Person has a constructor as shown below:
class Person
{
public:
Person(char *) {}
};
then Person myPer = NULL will compile just fine : http://www.ideone.com/586Pf
Now how much useful such class can be is up to you. One may exploit the above fact, and may come up with cool and useful (utility) class.