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

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!

Related

Pass parent pointer in derived constructor

So I was doing something like this:
Base * pParentPtr
// ... pParentPtr is used
// Cast result pointer
Derived* castedResult = (Derived*)pParentPtr;
// Copy the referenced object to stack object
Derived resultExplicitCopy = Derived(*castedResult);
// run Derived class functions
resultExplicitCopy.DeviredSpecialFunction();
// Free memory allocated by factory
delete pParentPtr;
Which means that the code uses pParentPtr but at the end we need it to be converted to Derived, then call a function that belongs only to Derived and then delete the initial pointer.
Although this works, the idea is to simplify the code. I thought on creating a contructor for Derived that takes a Base* for input:
Derived::Derived(Base* basePtr)
{
// Cast result pointer
Derived* castedResult = (Derived*)basePtr;
// Copy the referenced object to stack object
Derived resultExplicitCopy = Derived(*castedResult); // This looks bad
// run Derived class functions
resultExplicitCopy.DeviredSpecialFunction();
*this = resultExplicitCopy; // ??? this seems weird and dangerous
}
Creating a Derived instance inside the constructor seems like a bad idea, also reseting the whole object before it actually exists.
So, is there a way of pasing Base's pointer to Derived's constructor and properly building it?
I'd like it to look like this:
Base * pParentPtr
// ... pParentPtr is used
// Init derived with base
derivedInstance = Derived(pParentPtr);
// Free memory allocated by factory
delete pParentPtr;
The best way to deal with this would be to take a Base* in the constructor function and then manually setting the data fields in the constructor so for example. This is because when you call a constructor it will 'return' an instantiated version of that object to your specifications:
field1=basePtr->field1
I would avoid using the cast because it is a dangerous C cast as what it is doing is saying instead of treating what this pointer points to as having a Base type treat the memory as if it had a Derived type and if the memory doesn't match up there could be problems
This code is valid only if pParentPtr points to an object of class Derived. If it's true, then you can do one of these depending on the actual use case:
Directly call castedResult->DeviredSpecialFunction().
If you don't like the -> syntax for some reason (i'm assuming you're doing hobby project or it is not a peer-reviwed code, otherwise -> is perfectly fine), then you can "transform" pointer to a reference: Derived& resultExplicitCopy = (Derived&)(*castedResult) (note the two added ampersands).
Also I agree with comments noting that you should revise your design such that:
you don't blindly assume that pParentPtr points to Derived. Maybe the code above does the check already, but then still the following point holds:
you certainly shouldn't allow the construction of Derived form pointer Base if such construction blindly assumed that a pointer points to a Derived. Usually a class may be used in a different places in program, so a class's constructor should be clear in a way that you know what objects it may accept by looking at its signature. Having a proper parameter type makes it formally correct, and formal correctness actually makes things clearer. If constructor assumes its paremeter points to Derived, it should accept a Derived*, and accepting 'Base* would be incorrect as it allows a pointer to a non-Derived` object to be passed into it by mistake. In such a case the compiler can't help you by type checking.

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).

Constructing an object to return by value elsewhere

In a wrapper to interface the V8 JavaScript engine with C++ code, I'd like to call a C++ function passing it an object by value. The object is automatically constructed from data inside JavaScript.
The C++ function to call takes an object of type T and a template is used to generate an adapter function A, returning T by value. The problem is that the adapter function A needs to call a JavaScript function passing it another C++ function B as a callback. The object of type T is constructed in that function B. It cannot be returned back to A through JavaScript, which doesn't know how to handle the object of type T.
The simplest way is to have a local variable of type T inside function A. A pointer to it is given to B, which assigns a new value to the local variable, which A later returns, approximately like so (Some details omitted regarding how arguments are passed to callJavaScript and callback. In reality, T's constructor and thus the B function may take any number of more complicated types as parameters):
C++ code:
T A() {
T data;
callJavaScript("someJavaScriptFunction", &B, &data);
return data;
}
void B(T *data, int importantValue) {
*data = T(importantValue);
}
JavaScript code:
function someJavaScriptFunction(callback, dataRef) {
callback(dataRef, getImportantValueSomehow());
}
But what if the type T doesn't support assignment or even have a copy constructor? Is there a way to avoid unnecessary copying? I thought of allocating empty space inside function A as a local variable:
typename std::aligned_storage<sizeof(T), alignof(T)>::type data;
Function B could then construct the object in that space using placement new, but how can I return the resulting object from A using move semantics? How to call a possible destructor correctly?
My final idea was to use more template trickery to allocate space for parameters for type T's constructor inside function A, set them through pointers from B and finally construct the object inside A, but it will get nasty if data in some parameters goes out of scope when callJavaScript returns. Is there a solution for that?
EDIT: The point of all this is to get the contents of a JavaScript object into C++. Reading the object's properties from C++ requires looking them up by name using strings. A JIT-compiled function in V8 has more direct access to the object's fields and reads of the object's properties in someJavaScriptFunction get compiled into simple pointer reads. Then it can call the C++ callback with various parameters which are reasonably fast to convert from JavaScript value handles into C++ types.
EDIT2: The simple first idea is:
typename std::aligned_storage<sizeof(T), alignof(T)>::type data;
::new(&data) T(); // THIS LINE ACTUALLY PLACED IN ANOTHER FUNCTION
return(*reinterpret_cast<T *>(&data));
But should I call the destructor for the object T constructed in data, and when to call it, and how? This is a library and adding code to the recipient of the return value is not really an option.
I am not sure I understood completely your question, but it seems that you don't have a need to pass output parameters in your functions.
Simply have function A return a value as you already put in the question, and have B return a value.
Because of the "named return value optimization" there is no need for assignment operator nor copy constructors. That is, if your code satisfies the requirements for "NRVO" you would be fine:
T B(int importantValue) { return T{importantValue}; }
Does not need assignment operator nor copy constructor from T.
Then, change callJavascript to not require output parameters, but return a value, and then this will work without copy constructors or assignment operator:
T A() { A rv{callJavascript(&B)}; return rv; }
In general, make it so that your functions don't require output parameters, otherwise you require your types to have copy constructors and assignment operators, or to violate the type system.
By the way, make callJavascript such that it is a template that takes a callable as argument.
I ended up using a wrapper around A that handles calling placement new and A's destructor. It allows the library's user to supply any class A, as long as it has a move constructor. The full code of a working test and discussion about it are found in a newer, better formulated question Placement new, return by value and safely dispose temporary copies and its accepted answer.

Passing an object to a function, scope, and destructors

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.

What is the lifecycle of a C++ object?

I'm a seasoned C developer who is just now getting into C++, and I must admit, I'm very confused about how many ways there are to create, retain, and destroy C++ objects. In C, life is simple: assignment with = copies on the stack, and malloc/free manage data on the heap. C++ is far from that, or so it seems to me.
In light of that, here are my questions:
What are all the ways to create a C++ object? Direct/copy constructor, assignment, etc. How do they work?
What are all the different initialization syntaxes associated with all these types of object creation? What's the difference between T f = x, T f(x);, T f{x};, etc.?
Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers? In C, I got very used to throwing pointers around a lot, because pointer assignment is cheap but struct copying is less so. How do C++'s copy semantics affect this?
Finally, what are all these things like shared_ptr, weak_ptr, etc.?
I'm sorry if this is a somewhat broad question, but I'm very confused about when to use what (not even mentioning my confusion about memory management in collections and the new operator), and I feel like everything I knew about C memory management breaks down in C++. Is that true, or is my mental model just wrong?
To sum things up: how are C++ objects created, initialized, and destroyed, and when should I use each method?
First of all, your memory management skills are useful in C++, just they are a level below the C++ way of doing things, but they are there...
About your questions, they are a bit broad, so I'll try to keep it short:
1) What are all the ways to create a C++ object?
Same as C: they can be global variables, local automatic, local static or dynamic. You may be confused by the constructor, but simply think that every time you create an object, a constructor is called. Always. Which constructor is simply a matter of what parameters are used when creating the object.
Assignment does not create a new object, it simply copies from one oject to another, (think of memcpy but smarter).
2) What are all the different initialization syntaxes associated with all these types of object creation? What's the difference between T f = x, T f(x);, T f{x};, etc.?
T f(x) is the classic way, it simply creates an object of type T using the constructor that takes x as argument.
T f{x} is the new C++11 unified syntax, as it can be used to initialize aggregate types (arrays and such), but other than that it is equivalent to the former.
T f = x it depends on whether x is of type T. If it is, then it equivalent to the former, but if it is of different type, then it is equivalent to T f = T(x). Not that it really matters, because the compiler is allowed to optimize away the extra copy (copy elision).
T(x). You forgot this one. A temporary object of type T is created (using the same constructor as above), it is used whereever it happens in the code, and at the end of the current full expression, it is destroyed.
T f. This creates a value of type T using the default constructor, if available. That is simply a constructor that takes no parameters.
T f{}. Default contructed, but with the new unified syntax. Note that T f() is not an object of type T, but instead a function returning T!.
T(). A temporary object using the default constructor.
3) Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers?
You can use the same as in C. Think of the copy/assignment as if it where a memcpy. You can also pass references around, but you also may wait a while until you feel comfortable with those. What you should do, is: do not use pointers as auxiliary local variables, use references instead.
4) Finally, what are all these things like shared_ptr, weak_ptr, etc.?
They are tools in your C++ tool belt. You will have to learn through experience and some mistakes...
shared_ptr use when the ownership of the object is shared.
unique_ptr use when the ownership of the object is unique and unambiguous.
weak_ptr used to break loops in trees of shared_ptr. They are not detected automatically.
vector. Don't forget this one! Use it to create dynamic arrays of anything.
PS: You forgot to ask about destructors. IMO, destructors are what gives C++ its personality, so be sure to use a lot of them!
This is a fairly broad question, but I'll give you a starting point.
What's known in C as a "stack variable" is also called an object with "automatic storage". The lifetime of an object with automatic storage is fairly easy to understand: it's created when control reaches the point it's defined, and then destroyed when it goes out of scope:
int main() {
int foo = 5; // creation of automatic storage
do_stuff();
foo = 1;
// end of function; foo is destroyed.
}
Now, a thing to note is that = 5 is considered part of the initialization syntax, while = 1 is considered an assignment operation. I don't want you to get confused by = being used for two different things in the language's grammar.
Anyway, C++ takes automatic storage a bit further and allows arbitrary code to be run during the creation and destruction of that object: the constructors and destructors. This gives rise to the wonderful idiom called RAII, which you should use whenever possible. With RAII, resource management becomes automatic.
what are all these things like shared_ptr, weak_ptr, etc.?
Good examples of RAII. They allow you to treat a dynamic resource (malloc/free calls) as an automatic storage object!
Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers? In C, I got very used to throwing pointers around a lot, because pointer assignment is cheap but struct copying is less so. How do C++'s copy semantics affect this?
const references everywhere, especially for function parameters. const refs avoid copies and prevent modification of the object. If you can't use const ref, chances are a normal reference is suitable. If for some reason you want to reset the reference or set it to null, use a pointer.
What are all the ways to create a C++ object? Direct/copy constructor, assignment, etc. How do they work?
In short, all constructors create objects. Assignment doesn't. Read a book for this.
There are many ways of implicit object creating in C++ apart from explicit ones. Almost all of them use copy-constructor of the object's class. Remember: Implicit copying may require the copy constructor and/or assignment operator of a T type to be declared in public scope depending on where copying occurs. So in course:
a) explicit creation of a brand new object in stack:
T object(arg);
b) explicit copying of an existing object:
T original(arg);
...
T copy(original);
If T class has no copy constructor defined default implementation is created by compiler. It attempts to create an exact copy of the passed object. This is not always what programmer want, so custom implementation may be useful sometimes.
c) explicit creation of a brand new object in heap:
T *ptr = new T(arg);
d) implicit creation of a brand new object which constructor takes only one parameter and has no explicit modifier, for instance:
class T
{
public:
T(int x) : i(x) {}
private:
int i;
}
...
T object = 5; // actually implicit invocation of constructor occurs here
e) implicit copying of an object passed to a function by value:
void func(T input)
{
// here `input` is a copy of an object actually passed
}
...
int main()
{
T object(arg);
func(object); // copy constructor of T class is invoked before the `func` is called
}
f) implicit copying of an exception object handling by value:
void function()
{
...
throw T(arg); // suppose that exception is always raised in the `function`
...
}
...
int main()
{
...
try {
function();
} catch (T exception) { // copy constructor of T class is invoked here
// handling `exception`
}
...
}
g) Creation of a new object using assignment operator. I haven't used word 'copy' because in this case an assignment operator implementation of a particular type matters. If this operator is not implemented default implementation is created by compiler, btw it has the same behavior as default copy constructor.
class T
{
T(int x) : i(x) {}
T operator=() const
{
return T(*this); // in this implementation we explicitly call default copy constructor
}
}
...
int main()
{
...
T first(5);
T second = first; // assingment operator is invoked
...
}
Well, that's what I am able to remember without looking into Stroustrup's book. May be something is missed.
While I was writing this, some answer was accepted so I stop at this point. May the details I listed will be useful.