What compilation mechanism casts the result of new operator? - c++

Apparently, the new operator returns void*. So I was wondering what mechanism allows void* casting to A* when calling new A() to create a new instance of class A.
To illustrate:
// Example program
#include <iostream>
#include <string>
class A
{
public:
A() {}
};
void* createA()
{
return new A();
}
int main()
{
A* a1 = new A();
A* a2 = createA();
delete a1;
delete a2;
}
A* a1 = new A() compiles fine (obviously).
A* a2 = createA() does not reporting error: error: invalid conversion from 'void*' to 'A*' (obviously too...).
Actually, the first one also does a conversion from void* to A. What mechanism or rule allows the first conversion and rejects the second one?
That's probably a stupid question....if so, sorry about that.

What you have here is a new expression, which in turn invokes operator new (followed by the appropriate conversion), plus the constructor.
From cppreference.com:
::(optional) new (placement_params)(optional) ( type ) initializer(optional)
Attempts to create an object of type, denoted by the type-id type ...
It won't work if you manually invoke operator new, e.g.
A* a2 = operator new(sizeof(A));
won't compile either.

There is no cast here.
When the compiler sees a new expression, it first invokes the appropriate new operator (depending on the type and the arguments to the new keyword). That returns a pointer to a block of raw memory; such pointers are conventionally typed as void* since they do not refer to any object.
Then the appropriate constructors are executed (depending on the constructor arguments), starting with the base classes. The first step in executing a constructor is default-initializing the raw memory into which the object will be constructed. That includes initializing any internal metadata required by the object, such as its vtable if it includes a virtual method. Once that is finished, the memory region contains a nascent object, so this can be created with the correct type. Then the rest of the constructor can be executed (which might use this, either implicitly or explicitly).
Once all the constructors have been executed, the value of the new expression is the (typed) value of this.

Related

Why auto_ptr initialization using the assignment syntax is not allowed

I was reading through this book
C++ standard library book
And here is the part i can not understand:
Note that class auto_ptr<> does not allow you to initialize an object with an ordinary pointer by
using the assignment syntax.
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
std::auto_ptr<ClassA> ptr2 = new ClassA; //error
I don't understand why it is not allowed. What kind of pitfalls they were trying to avoid by not allowing initialization with assignment syntax
The fact that the assignment syntax cannot be used to initialize an auto_ptr from a raw pointer is a side effect of the constructor which takes a raw pointer being marked explicit. And the usual reason to mark a constructor as explicit is to prevent things like this:
void take_ownership(std::auto_ptr<ClassA> ptr) {
// the pointer is deleted when this function ends
}
void foo() {
ClassA obj;
take_ownership(&obj); // oops, delete will be called on a pointer to
// an object which was not allocated with new
}
The call to the take_ownership function is an error there, because of the explicit classifier on the std::auto_ptr constructor. Instead, you have to deliberately construct an auto_ptr and pass that to the function.
void foo() {
std::auto_ptr<ClassA> ptr(new ClassA);
take_ownership(ptr); // okay
}
Of course this is not completely impervious to abuse (you can still pass a non-newed object to the constructor of auto_ptr), it is at least easier to spot when an abuse is taking place.
By the way, std::auto_ptr is deprecated. It is a very broken class (due to limitations in the language at the time it was introduced). Use std::unique_ptr instead.
Here is how std::auto_ptr defined:
template< class T > class auto_ptr;
template<> class auto_ptr<void>;
Hence auto_ptr is a class type. Let's see its constructors:
explicit auto_ptr( X* p = 0 );
auto_ptr( auto_ptr& r );
template< class Y >
auto_ptr( auto_ptr<Y>& r );
template< class Y >
auto_ptr( auto_ptr_ref<Y> m );
Consider the first constructor. we can use a pointer to X type object as parameter to call this constructor:
std::auto_ptr<X> ptr1(new X); //ok
In the meanwhile, this first constructor is explicit, hence we cannot use a pointer to X type object implicitly to transform to auto_ptr<X>. In other words, we cannot initialize directly it via a pointer to X type object.
std::auto_ptr<X> ptr1 = new X; //error; cannot implicitly transform
I don't understand why it is not allowed.
At first direct initialization and copy initialization are not the same thing.
std::auto_ptr<ClassA> ptr1(new ClassA); //ok
This is direct initialization.
std::auto_ptr<ClassA> ptr2 = new ClassA; //error
This is copy initialization.
Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.
So if you want to initialize std::auto_ptr with raw pointer via copy initialization, converting constructor will be needed, but std::auto_ptr doesn't have it.
std::auto_ptr's constructor taking one raw pointer as parameter is explicit, implicit conversion is prohibited.
What kind of pitfalls they were trying to avoid by not allowing initialization with assignment syntax
Consider about the following code if implicit conversion is allowed:
void f1(ClassA* p) { ... }
void f2(std::auto_ptr<ClassA> p) { ... }
...
ClassA* p = new ClassA;
f2(p); // call the wrong function, ownership is transfered to auto_ptr implicitly
p->something(); // UB, p has been deleted
delete p; // UB

Returning a different class pointer by overloaded operator new in a class

Suppose i have this sample code:
class A
{
public:
static void* operator new(size_t sz);
private:
int xA;
float yA;
};
class B : public A
{
private:
int xB;
float yB;
};
void* A::operator new(size_t sz)
{
void* ptr = (void*)new B();
return ptr;
}
int main()
{
B* b = (B*) new A();
// Use b ..
delete b;
return 0;
}
Here the constructors will be called in that order (tested in VS2012):
A constructor
B constructor
A constructor
The first two constructors calls are because of the new B() in the overloaded operator new function.
But then the A constuctor will be called again on the pointer returned by the function because the overloaded operator new is supposed to return a pointer to free memory (without creating the object), so the constructor is called again.
If i use the pointer b in this example, is this undefined behaviour?
The code you posted has endless recursion, since you call
A::operator new from within A::operator new; class B
inherits the operator new from A.
Beyond that, you lie to the compiler, which results in undefined
behavior. After new A, you have a pointer to an object whose
type is A. You can legally convert its address to a B*, but
all you can do with that B* is convert it back to an A*;
anything else is undefined behavior.
And it's not clear what you're trying to achieve with the new
B in A::operator new. The compiler will consider any memory
returned from an operator new as raw memory; in this case, it
will construct an A object in it, and from then on out, all
you have is an A object. Any attempt to use it as a B
object is undefined behavior. (And of course, if you actually
need to destruct the B created in A::operator new, you can't
because you've overwritten it.
Finally: you don't have to declare operator new as static;
it implicily is, and it's idiomatic not to write the static in
this case. Similarly, when assigning the results of new B to
a void*, the conversion is idiomatic, and it is idiomatic not
to make it explicit. (It's also best to avoid the C style
casts, since they hide too many errors.)
In general , operator new() should not CREATE an object, it should create space for an object. Your code will overwrite a B object with an A object, and then use it as a B object, and yes, that would be "undefined" (probably covered in the docs under "casting an object to a different type that it wasn't originally created as).
This may appear to work in this particular case, but if the constructor of B is more complex (e.g. there are virtual functions in B), it would immediately fail to work correctly.
If you want to allocate memory for an object, you could do:L
void* A::operator new(size_t sz)
{
void* ptr = (void*)::new unsigned char[sz];
return ptr;
}
Now you are not calling two different constructors for the same object!
The contract of operator new is just the memory allocation, the initialization is done later by the new-expression (by calling the constructor) or by program code if you call the operator directly.
What you are trying to do cannot be done, not like that. You could redesign to use a factory member function that would return a pointer to a B object, for example...

Change 'this' pointer of an object to point different object

class C{
//methods and properties
}
void C::some_method(C* b){
delete this;
this = b;
}
This gives me follwing error when compiling:
error: lvalue required as left operand of assignment
My intention:
Say there are objects a and b of class C. The contents of the class C can be very huge and field by field copying can be very costly. I want all the contents of 'a' to be replaced by 'b' in an economical way.
Will default copy constructor do the intended task?
I found something called 'move constructor'
http://akrzemi1.wordpress.com/2011/08/11/move-constructor/
Perhaps, it might get the effect that I want.
The this-pointer is an implicit pointer to the object in whose context you are working, you cannot reassign it.
According to Stroustrup's bible (The C++ Programming Language, 3rd edition I have) this is expressed as
C * const this
meaning you have a constant pointer to your class C, so the compiler will complain if you try to change it.
EDIT:
As I was corrected, the above mentioned expression does not describe this fully correctly, for this is actually an rvalue.
You cannot change what this points to. I would also not know why you'd want to do this.
To quote the standard:
In the body of a non-static (9.3) member function, the keyword
this is a prvalue expression whose value is the address of the
object for which the function is called.
A "prvalue" is a pure rvalue, something like 42 or 3.14159.
In the same way you can't do something like 42 = x, you can't
assign to this; in both cases (at least conceptually), there
is no object whose value can change.
And I'm really curious as to what you expect to happen if
I write something like:
int
main()
{
C c1;
C c2
c1.some_method( &c2 );
}
Do you expect the address of c1 to somehow miraculously
change, and for c1 and c2 to be aliases to the same object?
(And c1.some_method( NULL ) is even more intreguing.)
You can't assign a different value to this as it point to the object itself, and this haven't any sense.
You could instantiate a new object and use its implicit this pointer instead.
Moreover, if you try to make a copy of object, you can overwrite operator=
class Foo
{
public:
[...]
Foo& operator=(const Foo& foo);
}
int main()
{
Foo foo;
foobar = foo; //invoke operator= overwrited method
}
The error says "You can't assign b to this". As far as I know, this is something you can't change, because it's not an actual pointer, but a self-reference.
Just use the usual approach instead of black magic and UB:
C* c1 = new C();
C* c2 = new C();
// do some work perhaps ...
delete c1;
c1 = c2;
Now c1 is an alias to c2 as you wanted. Be careful though when cleaning up memory so you don't end up deleting an object twice. You might perhaps consider smart pointers...

Copying similar classes in C++

I have two classes with similar structure.
class A{
int a;
char *b;
float c;
A(char *str) { //allocate mem and assign to b }
};
class B{
int a;
char *b;
float c;
B(char *str) { //allocate mem and assign to b }
B(B & bref) { //properly copies all the data }
};
I want to copy an object of B to the object of A. Are the following conversions fine?
A aobj("aobjstr");
B bobj("bobjstr");
bobj = aobj; //case 1
bobj = B(aobj); //case 2
Will the case 2 work? Will aobj be properly converted and interpreted as B & when B's copy constructor gets called?
EDIT: What about?
B bobj(aobj)
No, you can't implicitly convert between unrelated types without writing conversion constructors or conversion operators. Presumably, your compiler told you this; mine gave errors such as:
error: no match for ‘operator=’ in ‘bobj = aobj’
note: no known conversion for argument 1 from ‘A’ to ‘const B&’
error: no matching function for call to ‘B::B(A&)’
You could allow the conversion by giving B a conversion constructor:
class B {
// ...
B(A const & a) { /* properly copy the data */ }
};
If you can't change the classes, then you'll need a non-member function to do the conversion; but this is probably only possible if the class members are public. In your example, all the members, including the constructors, are private, so the classes can't be used at all. Presumably, that's not the case in your real code.
If you want to live dangerously, you might be able to get away with explicitly reinterpreting an A object as a B, since they are both standard-layout types with the same data members:
// DANGER: this will break if the layout of either class changes
bobj = reinterpret_cast<B const &>(a);
Note that, since your class allocates memory, it presumably needs to deallocate it in its destructor; and to avoid double deletions, you'll also have to correctly implement both a copy constructor and a copy-assignment operator per the Rule of Three.
If that all sounds like too much work, why not use std::string, which takes care of memory management for you?
If you tried to compile it you would find that none of this works. For one thing your constructors are private.
bobj = aobj; //case 1
This tries to call an assignment operator with the signature:
B& B::operator =(A const&)
This does not exist and compilation will fail.
bobj = B(aobj); //case 2
This tries to call A::operator B(), which does not exist and compilation will fail.
Finally:
B bobj(aobj)
This tries to call a constructor with the signature B::B(A const&), which does not exist and compilation will fail.
You say,
I can't change/modify class A and B, those are generated.
Then either the generator needs to be fixed or you're going to have to write your own adaptors.
You can do this by considering the following notes:
1) char* b makes a problem. When you copy aobj to bobj, the value of pointer aobj.b will be copied to bobj.b which means that they both refer to a same memory location and changing one like this: aobj.b[0] = 'Z' will cause bobj.b to change.
You can solve this by changing b from a pointer to a flat array:
//...
char b[MAXLEN];
//...
The better solution to this is to define a constructor (accepting the other type) and overload the assignment (=) operator, at least for class B, and handle the pointer assignment (allocate buffer for the new pointer and copy content to it).
2) UPDATED: A sample syntax is like this:
bobj = B(reinterpret_cast<B&> (aobj));
// or simply:
bobj = reinterpret_cast<B&> (aobj);
3) Note that this is dangerous, not safe, and not recommended. This means that the design of your solution should probably change. For example, A and B may both inherit from a common base class; B inherits from A; or B explicitly defines a constructor and an assignment operator for class A. These are far more recommended.

c++ inheritance question

I have a question about this:
class A
{
int a;
int* pa;
public:
A(int i):a(i) , pa(new int(a))
{
cout<<"A ctor"<<a<<endl;
}
~A()
{
delete pa;
cout<<"dtor\n";
}
int * &get()
{
return pa;
}
};
class B : public A
{
int b;
public:
B (A obj): A(obj) , b(0)
{
cout<<"B ctor\n";
}
~B()
{
cout<<"B dtor\n";
}
};
int main()
{
int i = 23 ;
A* p = new B(i);
}
Can tell me why the last line in main compiles? I pass an int into B's constructor which expects an A object instead. I believe that the int is translated to an A in B's constructor, but why?
Thanks in advance.
Avri.
Since you have not declared A constructor as explicit compiler is creating an anomymous instance of A using i and using it to initialize B instance. If you don't want the compiler to do these implicit conversions declare your costructor as explicit. Then you will get a compiler error.
Because A has a single parameter constructor which takes an int and isn't marked explicit you can implicitly convert an int to an A.
When you do new B(i), because the only viable constructor for B takes an A, an attempt is made to convert i to an A and construct the new B from that. This conversion is done by creating a temporary A using the constructor that takes an int.
When the B object is constructed, the base class A is copy constructed from the temporary A which means copying the member variables a and pa from the temporary A.
Strictly, because the constructor takes an A object by value, the temporary is, conceptually, copied again. The compiler may, however, eliminate the temporary by constructing the constructor parameter for B directly from i so the effect may well look like just a single copy.
This will cause a serious error because when the temporary A is destroyed, delete pa will cause the dynamically allocated int to be destroyed but the base class A of the newly allocated B object will still have a copy of this pointer which now no longer points at an invalid object. If the compiler doesn't eliminate one of the copies, a "double free" will happen immediately.
The key aspect of A is that it has a user-defined destructor that performs a resource action (deallocation). This is a strong warning that A needs a user-defined copy constructor and copy assignment operator because compiler generated version are likely not to work consistently with the design of A.
This is known as the "rule of three" which says that if you need a user-defined version of one of the destructor, copy constructor or copy assignment operator then you are likely to need user-defined versions of all of them.
Were you to attempt to free the dynamically allocated B object in your example, it would likely cause a "double free" error. In addition, A's destructor would need to be marked as virtual for a delete through a pointer to A to work correctly.
Since there is a conversion from int to A, implicitly your code is translated into
A* p = new B(A(i));