When do I need to initialize a pointer to nullptr? - c++

When I am reading some example code of Qt, I usually see they initialize a pointer to nullptr, for example:
QPushButton *startButton = nullptr;
I have some very basic idea of nullptr, but never really used it once since I have started to learn C++. So I wonder why they will initialize a pointer to nullptr instead of just doing like this: QPushButton *startButton;, What is the benefit of doing that and when do I need to initialize a pointer to nullptr?
Thanks in advance.

You need to initialize a pointer before you read it.
If you only sometimes initialize it to a sensible value before it is read, then initializing it to nullptr at the point of declaration makes sense since then you'll be able to detect nullptr as "not yet initialized to something reasonable".
Leaving the pointer uninitialized is no good if there's a path in your program that may then read it before it is initialized, since reading an uninitialized variable is Undefined Behaviour.

When do I need to initialize a pointer to nullptr?
In situations where you cannot initialize a pointer to an address of an object (possibly because that object does not yet exist, or perhaps only ever exists conditionally), but you need to be able to check whether the pointer does point to an object or not.
You can know that a pointer that points to null definitely does not point to an existing object. If you define the post-conditions and invariants of your program correctly, you'll be able to prove that a pointer always points to either null, or a valid object.
Null isn't the only option. Another option is to initialize to a static object that always exists. This is typical solution in node based (i.e. link based) data structures where that static object is called a sentinel node.

Related

should I check pointers in such situations?

I'm new to programming and game development in general
every time I read and hear that pointers are a nightmare I want to ask if it is necessary to check pointers in such cases as shown below?
// create a component of a certain type and return a pointer to data of this type
StaticMeshCompt = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
if (StaticMeshCompt)
{
// further work with the component
}
No, there's no need to check the pointer. The cases where CreateDefaultSubobject could return nullptr are :
The class passed is nullptr (It's guaranteed to be valid for any UObject).
The class has the abstract flag (Not the case for
UStaticMeshComponent).
Allocation itself fails due to lack of free memory (At that point,
you've got other problems).
As David G and ChrisMM said, it is necessary to check the pointer if the CreateDefaultSubobject function has a possibility of failing or returning a null pointer. If the function is known to always return a valid object, checking may not be necessary in that case.

Default initialization for a class pointer

I have seen the following construction in many code reviews:
ClassX *pObj;
ClassX obj;
pObj = &obj; //obj is not used in the rest of the code
Is the line below only used for initialization purposes?
pObj = &obj;
Why is it not initialized to NULL?
pObj = &obj; here pObj is pointer and it is pointing to obj.
Like below,
Note: Only for illustration purpose I have chosen address of obj,pObj as 0x1000,0x2000 respectively.
Why they do not initialize to NULL.
pObj can be initialized to NULL but eventually overwritten by pObj = &obj and hence no side effect occurs. But access to pObj before assignment causes UB.
pObj is a pointer to a properly initialised instance that can be used by the rest of the function or any called functions. NULL would mean there is no instance, a very different thing.
But why would you do this? One answer is that the rest of the code uses pointers and the author feels happier using pObj than using &obj.
Another may be that the pointer later gets assigned to a real object "usually". You didn't show us the later code so we have to speculate (or downvote). Perhaps the author thinks that having a valid temporary is less prone to crashes than having a null ptr if the assignment fails and the later code that uses the pointer is allowed to run, but this really is lazy programming, paying to initialise an object you never intend to use. If the real object is dynamically allocated, then the pointer might be valid outside the scope of this code, but the default instance would not be.
Sometimes construction/copy/move of objects is costly or impossible; thus pointer ClassX* pObj; can serve as a tool to quickly change target - as copying pointers is simple and cheap overall.
Say, in a loop pObj is frequently used and sometimes you need it to point to one object, then to another, and carryover it to next iterations. Or you have some complex rules that determine to which variable the pointer points to.
If one could've simply used obj instead of the pObj in the method without any issues - then it is simply poor coding practices to use pObj. Some might use it to save & when passing pointers... but that's barely an excuse. Regardless, I don't see much harm except for clutter.
Or they simply copied the code from elsewhere (that was also copied from another place...) without dwelling on it much as to why it is written in this way.

Getting the pointer to an object pointed towards by a smart pointer - Ivalue error

I am currently trying to call a sqlite3 library function, and it expects me to pass it a sqlite3**.
Here is my current code. I have one working part, and one part that gives me an error:
sqlite3 *sqlite = m_db.get();
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite))
{
}
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &(m_db.get()) ))
{
}
My m_db field looks like this:
std::unique_ptr<sqlite3> m_db = nullptr;
Of the two examples I displayed, the first one is working perfectly fine. However, the second gives me this error. Note that this is coming from the &(m_db.get()) part:
“Address expression must be an lvalue or a function designator”
I read up a little bit about lvalues and rvalues, but I can't seem to figure out why this syntax would not be possible. As far as I understood by now, the problem is that the return value of the .get() operation is merely only a temporary expression result, and therefore doesn't have an identifiable location in memory where I could fetch the adress from.
There has to be a way to achieve this in one statement, I guess.
Can anyone explain to me why this is not working and how I can possibly fix it?
The & operator can only be used with an lvalue (or with a qualified id when making pointers-to-member). The expression m_db.get() is an rvalue because it returns a pointer by value, not by reference, so you cannot take its address.
unique_ptr provides no method for accessing the underlying pointer as a reference, you'll need to store a copy somewhere as in your first example.
A smart pointer stores a pointer and returns it on get. What you want to do here is the opposite: you get a pointer from sqlite3_open and want to store it in a smart pointer. So you would do something like
sqlite3* db = nullptr;
sqlite3_open(..., &db);
m_db.reset(db);
As the main feature of the unique_ptr is to delete the contained pointer in its destructor, I'm not sure if it makes sense to use it here. As far as I understand it, you are supposed to call sqlite3_close on the returned pointer, not delete it.
There has to be a way to achieve this in one statement, I guess.
I'm not quite sure about that; the point about temporary values really might be that it takes a statement to get a permanent one.
Also, you're messing with the semantics of the smart pointer, which you shouldn't do – .get should really not be used here.
Soooo, what I'd do is rely on C++ scoping here, and don't care about the fact that I declare a "normal" pointer first to make a smart pointer later.
your_class::initialize_db() {
sqlite3 *sqlite;
int retval = sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite);
if(retval == SQLITE_OK)
m_db = std::unique_ptr<sqlite3>(sqlite);
}
An lvalue is basically something which can appear on the left hand side of the assignment operator. So the error says that you can only retrieve the address of something which can be assigned to, or a function. It would have worked if you had member access to the sqlite3* pointer inside the unique_ptr, but you don't, and for good reason.
More to the point, you should not use a smart pointer in this case. If sqlite3_open requires an sqlite3** argument, then it means that the function will provide a value for the sqlite3* pointer. Basically it is an out parameter form C# or other such languages. It would have been clearer for it to be provided as a function result, but that was taken away by the result code. This is all well and good, but the smart pointer wants to have control over this value. You set the value once at initialization, but after that, the smart pointer takes care of it. And it needs to do this in order to maintain its constraints: uniqueness of ownership, deallocation when the pointer itself goes out-of-scope etc. If you basically go and overwrite the sqlite3* pointer inside, then that can't happen anymore, because the smart pointer has no way of intercepting the overwrite and deallocating the object it is currently using.

Releasing a CSharedPtr in Marmalade

I'm looking at Marmalade's implementation of CSharedPtr, which purports to perform reference counting. The documentation states that:
When the last CSharedPtr<> referring to a particular object goes out of scope, the reference count reaches zero, and the the delete operator is called on the object.
Is there any way to release the object without it going out of scope? I don't seem to be able to set it to NULL.
Try constructing a new CSharedPtr using the constructor that lets you pass in a pointer and then assigning that to the one you want to set to null.
CSharedPtr<T> cNullPtr( NULL );
existingPtr = cNullPtr;

C++ Pointer (Pass By Reference) Question

A pointer that is passed-in-by-reference. Why? aren't pointers just references anyways? What's really happening to this parameter?
void someFunc(MyPtr*& Object)
{
}
Simply speaking, it gives you the ability to change the pointer itself: it can be changed to point to another location in the function.
And the change will be reflected outside.
It enable you to:
void someFunc(MyPtr*& Object)
{
//Modify what Object is pointing to
Object=&old_Object;
//You can also allocate memory, depending on your requirements
Object=new MyPtr;
//Modify the variable Object points to
*Object=another_object;
}
Other's will have to vote to verify this cause I'm a bit rusty on my C++ but I believe the idea here is you'd pass in a pointer by reference, that is instead of creating a new space to store the pointer itself you use a reference to the pointer so if you were to modify the pointer not just the value it would be modified after returning from the function, whereas otherwise all you could do is modify the value at position passed in. Hope that makes sense.
The difference to passing just a pointer is that if the pointer is changed (Object = x) then this change will be seen by the calling function. You could achieve the same when you pass MyPtr** Object and dereference the pointer *Object = x;. With the second approach you could pass NULL to the function. This is not possible for references.
You are not quite right. The pointer content is passed by reference but the pointer itself is still passed by value, i.e. reassinging it to some other pointer will not be reflected upon the exit from the method because the pointer will be set to point to the same memory block as before the call. Think of it as a simple int variable. However with &* or ** you can reassign the pointer and that will be visible outside the scope of this method.
Why?
For the same reason that you would pass in anything else by reference.
aren't pointers just references anyways?
Dear god, no. Not even remotely the same thing. Look, you can try to build a mental model of a reference by starting with a pointer, but by the time you've fixed up all the differences, you have a horrible illogical mess.
References are a much simpler and more intuitive concept, and there are only "historical reasons" for trying to understand pointers before them. Modern C++ uses raw pointers only rarely, and treats them as an implementation detail as much as possible.
A reference is another name for an already-existing thing. That's it. When used as a function parameter, they thus allow the called function to refer to the caller's data.
It also means the pointer can be 0 (NULL) which can having meaning to the method. A reference must always be valid and cannot be made 'nothing'