Passing an object to a function, scope, and destructors - c++

Recently I've been getting back into programming in C++ and have come across interesting while programming something else.
In the code below I defined a class with a pointer member that gets deleted in the class' destructor.
I have also defined a function which takes a Test_Object object as an argument which calls one of the get_val() method which does nothing more but report the value held in the memory address the pointer is pointing to.
Now when I call the function twice it correctly prints the value in held by the internal pointer correctly once, then just core dumps after the second.
Correct me if I'm wrong, but I believe that the reason this happens is because after the first time the function is called the object's destructor is called because the object has gone out of scope and is essentially destroyed.
The only way I could think of preventing this is by passing the object by reference. Is there any other way to prevent this from happening? It seems a bit dangerous to simply pass the object by reference since the object can be modified in that function call which could lead to headaches later on.
I've tried making the argument const, however I get an error stating that ‘const Test_Object’ as ‘this’ argument of ‘void Test_Object::get_val()’ discards qualifiers argument.get_val();
#include <iostream>
using namespace std;
class Test_Object
{
private:
int *internal_pointer;
public:
Test_Object(int value)
{
internal_pointer = new int;
*internal_pointer = value;
}
~Test_Object()
{
delete internal_pointer;
internal_pointer = NULL;
}
void get_val() { cout<<*internal_pointer<<endl; }
};
void test_outsider(Test_Object argument)
{
argument.get_val();
}
int main()
{
Test_Object test = Test_Object(4);
test_outsider(test);
test_outsider(test);
return 0;
}

To start with you should read about the rule of three.
As for your problems it's because the objects are copied, and since you don't provide your own copy-constructor the pointer is copied "as-is" leaving multiple copies pointing to the same allocated memory. When one of those copies delete the allocated memory in the destructor, the pointer is invalidated for all copies.
You can solve the problem by implementing a copy-constructor and a copy-assignment operator.

Related

Pass reference to function that takes `std::unique_ptr`

I have a reference to my object of type MyType, but I need to call a function, say myFunction that takes a std::unique_ptr<MyType>. What is the correct way to call myFunction? My attempt below seems to cause an "invalid pointer" error:
#include <memory>
class MyType {};
MyType myGlobalObj;
MyType& myGetter () {
return myGlobalObj;
}
void myFunction (std::unique_ptr<MyType> ptr) {
// Do important stuff
}
int main () {
MyType& myObj = myGetter();
std::unique_ptr<MyType> myPtr;
myPtr.reset(&myObj);
myFunction(std::move(myPtr)); // This causes "invalid pointer" at run time.
myPtr.release();
return 0;
}
What you are trying to do is not possible without either doing a (deep-)copy of myGlobalObj or modifying myFunction.
A std::unique_ptr takes ownership of the memory that is used to store the contained object. That means that the std::unique_ptr may free (or reallocate, or whatever) the memory that it 'owns'. What it would do in your case: As soon as the ptr variable goes out of scope at the end of myFunction, it will attempt to free the memory that it points to. Since myGlobalObj is a global variable, its memory may never be freed (before a controlled shutdown of your program…)
Thus, you should not ever wrestle a global object into a std::unique_ptr (or a std::shared_ptr, for that matter). If there is really no way of refactoring that method to take anything else than a std::unique_ptr, you must make a copy (on the heap!) of myGlobalObj, wrap that into a std::unique_ptr, and pass it to myFunction. Keep in mind that this way, myFunction loses the ability to modify myGlobalObj.

Initializing objects with virtual functions on pre-allocated memory without placement new operator - is that possible? If not, why

Let's say there's a simple class hierarchy, and a state object that uses the derived class;
struct base_class {
int Value;
base_class() { this->Value = 1; }
virtual void Func() { printf("Base\n"); };
};
struct derived_class : base_class {
int Value;
derived_class() { this->Value = 2; }
void Func() { printf("Derived\n"); }
};
struct state {
int a,b,c;
derived_class Object;
};
Now, let's assume that there's an allocator, that is not aware of the types and just returns 0-initialized allocated block memory of required size.
state *State = (state *)Allocate(sizeof(state));
And now, to properly initialize the vtable pointers we must construct the object.
I've seen it done with placement new operator. And it does indeed seem to work.
However, I'm interested why if I construct the state object like this
*State = {};
The State is initialized perfectly, I see the values set to 1 and 2. But the _vfprt is 0. Even if I step into the constructor, the this pointer seems to have everything correctly set up, _vfprt points to the correct method and all.
But when I return from the constructor, the _vfprt fails to get copied itho the State object. Everything else is there. But the _vfprt is 0;
So I'm just wondering if there's a special magical copy constructor that's invoked whenever new() operator is used. And if there is one, how can I use it.
I use this kind of initialization everywhere in my app, and honestly adding placement new everywhere just to support one small class is a pain in the butt. the {} call is much cleaner (and shorter), and it makes the allocation calls so much easier. If it's not possible to make this work, I'm ok with that. I'm just confused as to why the vtable pointer is not copied back after we return from the constructor.
If anyone could explain why this happens, that would be great.
Thanks!
*state = {} is an assignment, not a construction. An assignment cannot change the dynamic type1 on an object. The virtual pointer only depends on the dynamic type of the object. So it is not necessary to copy the virtual pointer in an assignment.
In an assignment, the object on the left side is supposed to be within its life time. The placement new expression starts an object's life time, an assignment does not. In the assignment *state = {}, the compiler assumes that an object already exists at the memory location pointed to by state. So the compiler assumes that the virtual pointer has already been initialized. The placement new will construct the object, which initializes the virtual pointer.
1 The type of the most derived object, here it is state.
You invoke undefined behaviour! What you do by this assignment (*State = { };) is equivalent to: (*State).operator=({ });. As you notice, you call a function at an object of which the lifetime never began (just the same as if you did (*state).someFunction();), as no constructor ever was successfully called (well, wasn't called at all).
Peeking a bit under the hoods:
As your object is polymorphic, it receives a pointer to a virtual function table. Once an object is constructed, though, that pointer for sure won't change any more (objects cannot change their type as long as they live). So an assignment operator wouldn't need to change it! So the pointer to the vtable only gets installed inside the constructor, but as you never called one, it won't get installed at all.
This will apply for both the class itself (in given case without vtable, though) as well as for members or base classes (for all of which the assignment operators, which get called recursively, suffer from the same problem).

C++ class destructor delete member if "owner"?

I know in C++ that a pointer is just that: a pointer to a memory location, and there is no concept of "owners". But consider the following situation (not necessarily good code):
class A {
public:
A(){}
~A()
{ if(myObject!=nullptr)
delete myObject;
}
void createMember()
{myObject=new CrazyCustomClass();}
CrazyCustomClass *getMember()
{return myObject;}
private:
CrazyCustomClass *myObject=nullptr;
}
If it makes a difference, CrazyCustomClass does NOT have a copy constructor, as it makes no sense to copy it. So pretty straight forward - I have a class that, at some point after instantiation, may call new to instantiate a member of type CrazyCustomClass *
The problem is that if at some point I have a copy of class A created (which is fine - I want to be able to copy class A). When that copy is deleted, so is the object pointed to by the original class A instantiation. For example:
void StupidFunction(A *firstObject){
//This is NOT a real function, it simply illustrates the effect of a third-party library function
//create a new object that is a copy of first object
A secondObject(*firstObject);
<do whatever with second object>
//secondObject goes out of scope here and gets deleted.
}
A *firstObject=new A();
firstObject->createMember();
stupidFunction(firstObject);
CrazyCustomClass *customObject=firstObject.getMember(); //this is now an invalid pointer
In the above example, the StupidFunction is from a third-party library, the idea being that it gives a "temporary" copy of the object that you can work with without messing with the original object, which is good. Class A and CrazyCustomClass are both my code and can be changed at will. Unfortunately, when the "temporary" copy is deleted, the way I wrote my destructor causes problems.
My first thought was to use shared_ptr, something like so:
std::shared_ptr<CrazyCustomClass> sharedObject=std::make_shared<CrazyCustomClass>(new CrazyCustomClass);
...but that gave me an error when compiling:
candidate constructor (the implicit copy constructor) not viable: no
known conversion from 'CrazyCustomClass *' to 'const CrazyCustomClass'
for 1st argument; dereference the argument with *
and if I do dereference the argument with *, it gives me an error about the copy constructor of "CrazyCustomClass" being deleted, which is true - there is no sensible way to copy CrazyCustomClass.
So my question is: how can I refactor class A such that myObject gets properly deleted when firstObject goes out of scope, but not when any "temporary" copies of A get deleted?
Using a shared_ptr is in fact a solution to this problem, however the code as attempted in the original question is incorrect. There are two (at least) different ways to initialize a shared_ptr (ref: https://msdn.microsoft.com/en-us/library/hh279669.aspx). First, you can do it by using new as a constructor argument:
shared_ptr<CrazyCustomClass> myObject(new CrazyCustomClass)
Secondly, and this is the generally preferred method, you can use the make_shared function (as attempted in the original post), which takes not the new object, but the arguments to be passed to the object constructor, in this case nothing:
shared_ptr<CrazyCustomClass> myObject=make_shared<CrazyCustomClass>()
The original code simply got these two methods mixed up, thus the errors about copy constructor: it was trying to instantiate a new CrazyCustomClass object with a pointer to a CrazyCustomClass object as the constructor argument.
Once using a shared_ptr, the delete in the destructor must be removed.
Tip of the hat to #tkausl and #alterigel for pointing out the error in the comments on the question!

Return object with 2 optional ctors in function

I have function in c++ with 2 optional c'tor of an object I've built (one with something in vector "vals" and other without).
...
RecievedMessage a(sc, type);
if (!vals.empty()){
//a.~RecievedMessage();
RecievedMessage a(sc, type, vals);
}
return &a;
}
the line in // is optional.
Would it work (with or without the optional line)? Why? If no, how to fix it without setter for "vals"?
thanks a lot.
No, it wouldn't work.
RecievedMessage a(sc, type);
// Here we construct 'a'
if (!vals.empty()){
//a.~RecievedMessage();
// If we enable this line, we destroy 'a'
RecievedMessage a(sc, type, vals);
// Here we construct a second 'a' that only exists in this block
}
// End of block: The inner 'a' is destroyed here automatically
return &a;
}
// End of block: The outer 'a' is destroyed here, again.
Destroying an object twice has undefined behavior. You don't want that.
If you don't call the destructor manually, the outer a is only destroyed once, which is good.
But in either case, RecievedMessage a(sc, type, vals); has nothing to do with the outer a and merely creates another variable.
There would be ways to work around that, but the final line of your code makes it all pointless:
return &a;
You're returning the address of a local variable. This is broken in and of itself: When the function returns, all of its local variables are destroyed automatically, so what you're returning is an invalid pointer.
Your code is all over the place, but what I think you're looking for is something like this:
ReceivedMessage *MakeReceivedMessage (foo sc, bar type, vector<whatever>& vals)
{
if (vals.empty())
return new ReceivedMessage (sc, type);
return new ReceivedMessage (sc, type, vals);
}
Of course, it would be better in this example to just have a single constructor and have the object test whether vals is empty when appropriate, but, in general, you can call whatever constructor you like whenever you like. Just manage your object lifetimes properly (and don't - ever - return a pointer to an object on the stack).
Example usage (to manage the lifetime of the object returned properly):
std::unique_ptr<ReceivedMessage> MyReceivedMessage (MakeReceivedMessage (...));
MyReceivedMessage->DoFunkyStuffWithMessage ();
....
Or, as melpomene points out, you can return a std::unique_ptr<ReceivedMessage> in the first place. Some (many?) would prefer that. You can construct it with std::make_unique.
There are three main issues with your code right now:
First of all, your commented out call to the destructor ~ReceivedMessage() should not be there at all. In C++, the destructor of objects is automatically called when an object's lifetime ends (either when it goes out of scope, or when delete is called if it was dynamically allocated with new). While there are some situations where explicitly calling a destructor is necessary ("placement new" for example), these are situations you're very unlikely to come across.
Secondly, your RecievedMessage a(sc, type, vals); declaration in the inner if does not replace the value of a in the outer scope. This just creates another variable of the same name which shadows the outer a, while return &a; in the outer scope can only refer to the outer a. The inner a no longer exists at this point as it has gone out of scope.
A way to fix this issue is to instead assign a new value to a by using the = operator and constructing a temporary ReceivedMessage:
if (!vals.empty()) {
a = ReceivedMessage(sc, type, vals);
}
This should work as long as a correct operator= is defined (implicitly or otherwise) for ReceivedMessage.
Thirdly, your function is returning a pointer to the local variable a. Since objects in C++ are destroyed as soon as they go out of scope, a no longer exists by the time the function has returned, so the ReceivedMessage * pointer the calling code obtains is invalid and it would be undefined behaviour to dereference that pointer and make use of it.
There are a couple of fixes to this issue:
The first option is instead of returning a pointer (ReceivedMessage *), just return a ReceivedMessage by value.
ReceivedMessage foo()
{
ReceivedMessage a(123);
return a;
}
This should work as long as a correct copy or move constructor is defined (implicitly or otherwise) for ReceivedMessage.
The second option is to make use of std::unique_ptr, and make your function instead return std::unique_ptr<ReceivedMessage>.
#include <memory>
std::unique_ptr<ReceivedMessage> foo()
{
std::unique_ptr<ReceivedMessage> a;
if (vals.empty()) {
a = std::make_unique<ReceivedMessage>(sc, type);
} else {
a = std::make_unique<ReceivedMessage>(sc, type, vals);
}
return a;
}
The advantage to this approach is that unique_ptr is nullable, so you can create a null unique_ptr without having to construct a ReceivedMessage straight away. Additionally, you can move and assign unique_ptr values safely without having a correct operator= or a correct copy / move constructor defined.
The calling code may look like this, when using unique_ptr:
std::unique_ptr<ReceivedMessage> message = foo();
foo->bar();
as opposed to the following when using ReceivedMessage directly:
ReceivedMessage message = foo();
foo.bar();

how can I check if an object exists in C++

I am trying to write a function that will check if an object exists:
bool UnloadingBay::isEmpty() {
bool isEmpty = true;
if(this->unloadingShip != NULL) {
isEmpty = false;
}
return isEmpty;
}
I am pretty new to C++ and not sure if my Java background is confusing something, but the compiler gives an error:
UnloadingBay.cpp:36: error: no match for ‘operator!=’ in ‘((UnloadingBay*)this)->UnloadingBay::unloadingShip != 0’
I can't seem to figure out why it doesn't work.
Here is the declaration for class UnloadingBay:
class UnloadingBay {
private:
Ship unloadingShip;
public:
UnloadingBay();
~UnloadingBay();
void unloadContainer(Container container);
void loadContainer(Container container);
void dockShip(Ship ship);
void undockShip(Ship ship);
bool isEmpty();
};
It sounds like you may need a primer on the concept of a "variable" in C++.
In C++ every variable's lifetime is tied to it's encompassing scope. The simplest example of this is a function's local variables:
void foo() // foo scope begins
{
UnloadingShip anUnloadingShip; // constructed with default constructor
// do stuff without fear!
anUnloadingShip.Unload();
} // // foo scope ends, anything associated with it guaranteed to go away
In the above code "anUnloadingShip" is default constructed when the function foo is entered (ie its scope is entered). No "new" required. When the encompassing scope goes away (in this case when foo exits), your user-defined destructor is automatically called to clean up the UnloadingShip. The associated memory is automatically cleaned up.
When the encompassing scope is a C++ class (that is to say a member variable):
class UnloadingBay
{
int foo;
UnloadingShip unloadingShip;
};
the lifetime is tied to the instances of the class, so when our function creates an "UnloadingBay"
void bar2()
{
UnloadingBay aBay; /*no new required, default constructor called,
which calls UnloadingShip's constructor for
it's member unloadingShip*/
// do stuff!
} /*destructor fires, which in turn trigger's member's destructors*/
the members of aBay are constructed and live as long as "aBay" lives.
This is all figured out at compile time. There is no run-time reference counting preventing destruction. No considerations are made for anything else that might refer to or point to that variable. The compiler analyzes the functions we wrote to determine the scope, and therefore lifetime, of the variables. The compiler sees where a variable's scope ends and anything needed to clean up that variable will get inserted at compile time.
"new", "NULL", (don't forget "delete") in C++ come into play with pointers. Pointers are a type of variable that holds a memory address of some object. Programmers use the value "NULL" to indicate that a pointer doesn't hold an address (ie it doesn't point to anything). If you aren't using pointers, you don't need to think about NULL.
Until you've mastered how variables in C++ go in and out of scope, avoid pointers. It's another topic entirely.
Good luck!
I'm assuming unloadingShip is an object and not a pointer so the value could never be NULL.
ie.
SomeClass unloadingShip
versus
SomeClass *unloadingShip
Well, you don't have to write so much code to check if a pointer is NULL or not. The method could be a lot simpler:
bool UnloadingBay::isEmpty() const {
return unloadingShip == NULL;
}
Plus, it should be marked as "const" because it does not modify the state of the object and can be called on constant instances as well.
In your case, "unloadingShip" is an object of class "UnloadingShip" which is not dynamically allocated (except when the whole class "UnloadingBay" is allocated dynamically). Thus, checking if it equals to NULL doesn't make sense because it is not a pointer.
For checking, if an object exists, you can consider going this way:
create a pointer to your object:
someClass *myObj = NULL // Make it null
and now where you pass this pointer, you can check:
if(!myObj) // if its set null, it wont pass this condition
myObj = new someClass();
and then in case you want to delete, you can do this:
if(myobj)
{
delete myObj;
myObj = NULL;
}
so in this way, you can have a good control on checking whether your object exists, before deleting it or before creating a new one.
Hope this helps!