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.
Related
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.
Below is an example code (for learning purpose only). Classes A and B are independent and have copy contructors and operators= .
class C
{
public:
C(string cName1, string cName2): a(cName1), b(new B(cName2)) {}
C(const C &c): a(c.a), b(new B(*(c.b))) {}
~C(){ delete b; }
C& operator=(const C &c)
{
if(&c == this) return *this;
a.operator=(c.a);
//1
delete b;
b = new B(*(c.b));
//What about this:
/*
//2
b->operator=(*(c.b));
//3
(*b).operator=(*(c.b));
*/
return *this;
}
private:
A a;
B *b;
};
There are three ways of making assignment for data member b. In fact first of them calls copy constructor. Which one should I use ? //2 and //3 seems to be equivalent.
I decided to move my answer to answers and elaborate.
You want to use 2 or 3 because 1 reallocated the object entirely. You do all the work to clean up, and then do all the work to reallocate/reinitialized the object. However copy assignment:
*b = *c.b;
And the variants you used in your code simply copy the data.
however, we gotta ask, why are you doing it this way in the first place?
There are two reasons, in my mind, to have pointers as members of the class. The first is using b as an opaque pointer. If that is the case, then you don't need to keep reading.
However, what is more likely is that you are trying to use polymorphism with b. IE you have classes D and E that inherit from B. In that case, you CANNOT use the assignment operator! Think about it this way:
B* src_ptr = new D();//pointer to D
B* dest_ptr = new E();//pointer to E
*dest_ptr = *src_ptr;//what happens here?
What happens?
Well, the compiler sees the following function call with the assignment operator:
B& = const B&
It is only aware of the members of B: it can't clean up the no longer used members of E, and it can't really translate from D to E.
In this situation, it is often better to use situation 1 rather than try to decern the subtypes, and use a clone type operator.
class B
{
public:
virtual B* clone() const = 0;
};
B* src_ptr = new E();//pointer to D
B* dest_ptr = new D();//pointer to E, w/e
delete dest_ptr;
dest_ptr = src_ptr->clone();
It may be down to the example but I actually don't even see why b is allocated on the heap. However, the reason why b is allocate on the heap informs how it needs to be copied/assigned. I think there are three reasons for objects to be allocated on the heap rather than being embedded or allocated on the stack:
The object is shared between multiple other objects. Obviously, in this case there is shared ownership and it isn't the object which is actually copied but rather a pointer to the object. Most likely the object is maintained using a std::shared_ptr<T>.
The object is polymorphic and the set of supported types is unknown. In this case the object is actually not copied but rather cloned using a custom, virtual clone() function from the base class. Since the type of the object assigned from doesn't have to be the same, both copy construction and assignment would actually clone the object. The object is probably held using a std::unique_ptr<T> or a custom clone_ptr<T> which automatically takes care of appropriate cloning of the type.
The object is too big to be embedded. Of course, that case doesn't really happen unless you happen to implement the large object and create a suitable handle for it.
In most cases I would actually implement the assignment operator in an identical form, though:
T& T::operator=(T other) {
this->swap(other);
return *this;
}
That is, for the actual copy of the assigned object the code would leverage the already written copy constructor and destructor (both are actually likely to be = defaulted) plus a swap() method which just exchanges resources between two objects (assuming equal allocators; if you need to take case of non-equal allocators things get more fun). The advantage of implementing the code like this is that the assignment is strong exception safe.
Getting back to your approach to the assignment: in no case would I first delete an object and then allocate the replace. Also, I would start off with doing all the operations which may fail, putting them into place at an appropriate place:
C& C::operator=(C const& c)
{
std::unique_ptr tmp(new B(*c.b));
this->a = c.a;
this->b = tmp.reset(this->b);
return *this;
}
Note that this code does not do a self-assignment check. I claim that any assignment operator which actually only works for self-assignment by explicitly guarding against is not exception-safe, at least, it isn't strongly exception safe. Making the case for the basic guarantee is harder but in most cases I have seen the assignment wasn't basic exception safe and your code in the question is no exception: if the allocation throws, this->b contains a stale pointer which can't be told from another pointer (it would, at the very least, need to be set to nullptr after the delete b; and before the allocation).
b->operator=(*(c.b));
(*b).operator=(*(c.b));
These two operations are equivalent and should be spelled
*this->b = *c.b;
or
*b = *c.b;
I prefer the qualified version, e.g., because it works even if b is a base class of template inheriting from a templatized base, but I know that most people don't like it. Using operator=() fails if the type of the object happens to be a built-in type. However, a plain assignment of a heap allocated object doesn't make any sense because the object should be allocated on the heap if that actually does the right thing.
If you use method 1 your assignment operator doesn't even provide the basic (exception) guarantee so that's out for sure.
Best is of course to compose by value. Then you don't even have to write your own copy assignment operator and let the compiler do it for you!
Next best, since it appears you will always have a valid b pointer, is to assign into the existing object: *b = *c.b;
a = c.a;
*b = *c.b;
Of course, if there is a possibility that b will be a null pointer the code should check that before doing the assignment on the second line.
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...
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));
I've got a class A, which consists of objects B and C. How to write a constructor of A that gets B and C objects? Should I pass them by value, by (const) reference, or a pointer? Where should I deallocate them?
I thought about pointers, because then I could write:
A a(new B(1,2,3,4,5), new C('x','y','z'))
But I don't know whether it's a good practice or not. Any suggestions?
Usually you pass by const reference:
A a(B(1,2,3,4,5), C('x','y','z'))
No need for pointers here.
Usually you store values unless copying is too inefficient.
The class definition then reads:
class A {
private:
B b;
C c;
public:
A(const B& b, const C& c): b(b), c(c) { }
};
Should I pass them by value, by (const) reference, or a pointer?
By const reference if object is big
by value if object is small
by const pointer if it is an optional argument that can be zero (i.e. "NULL")
by pointer if it is an optional argument that can be zero but will be owned (i.e. deallocated) by constructed class.
Please note that if your class have internal instances of B and C, then passing them by reference, value or const reference, will most likely involve using copy constructor or assignment operator. Which won't be necessary with pointers.
A a(new B(1,2,3,4,5), new C('x','y','z'))
Normally(i.e. not always) it is a bad idea, because:
if A doesn't deallocate arguments, you have a memory leak.
If A takes ownership of arguments and deallocates them, then you won't be able to pass values allocated on stack as arguments. Still, depending on your code design this may be acceptable (Qt 4 frequently takes ownership of objects created with new)
Where should I deallocate them?
The best idea is to make sure that compiler deallocates arguments automatically for you.
This means passing by reference, const reference or by value. Or using smart pointers.
What you pass in depends on your needs.
Do you need a copy of the thing you are passing in? Then pass by const-reference.
struct A
{
A(const B& b, const C& c) : m_b(b), m_c(c) {}
private:
B m_b;
C m_c;
};
And construct it like this:
A myA(B(1,2,3), C(4,5,6));
If you want your A object to refer to some other B and C objects (but not own them) then use pointers (or possibly references).
Edit: The examples given here do not respect the rule of the Big Three (thanks #Philipp!). If the definition of A is used as given below, the code will crash on copy construction for A, or on assignment for A. To define the code correctly, the assignment operator and copy constructor should be explicitly defined for A (or explicitly forbidden - declared as private and never implemented). (end Edit)
Should I pass them by value, by
(const) reference, or a pointer?
If A uses B and C, then hold them by reference or pointer inside of A. To choose between reference and pointer, see how B and C are allocated.
If they are local stack objects constructed in the same scope as A, then pass them by const reference.
If they are dynamically allocated objects that A uses, make A own them: pass them by pointers, and have A's destructor delete them.
If they are optional components of A, pass them by pointer (that can be null).
If A is not responsible of deleting them, pass them by * const.
Where should I deallocate them?
Usually where you no longer need them :).
If they are needed past the scope of A (if they are external objects that A uses) then delete them when A's scope is complete.
If they are owned by A, delete them in the destructor for A. It may make sense to also delete them during the lifetime of A, if the pointers should be changed.
Here's an example, where B is a replaceable component injected into A (and owned by A) and C is an optional component owned by A (but injected into A also).
("owned by" means A is responsible for deleting both objects)
class B;
class C;
class A
{
B* b;
C* c;
public:
A(B* const bb, C* const cc = 0) // cc is optional
: b(bb), c(cc)
{
}
void resetB(B* const bb = 0)
{
delete b;
b = bb;
}
~A()
{
resetB();
delete c;
}
};
{
A a(new B, new C);
a.resetB(); // delete B
a.resetB(new B); // delete former B and set a new one
} // both members of A are deleted
But I don't know whether it's a good
practice or not. Any suggestions?
It's up to you really, but you can write A a(B(1, 2, 4), C(1, 2, 3)) as easy as A a(new B(1, 2, 4), new C(1,2,3)); (in the former case - the one without new - the A::b and A::c should be references or objects/values inside the class, and A should not delete them at all).
The question should not be if you want to write the statement with dynamic allocation for B and C but if you need to. Dynamic allocation is slow and if you don't have a requirement for it you shouldn't do it.