Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);
Related
I have this:
struct Point
{
size_t x;
size_t y;
~Point()
{
std::cout << "Destro" << "\n";
}
};
const Point& getPoint()
{
return { 100, 120 };
}
int main()
{
Point p = getPoint();
std::cout << "Exit" << "\n";
}
and the result is
Destro
Exit
Destro
I'm basically trying to make the getPoint method not have to copy the Point class.
Here is what's happening so far:
Point Created
Point copied to the result
Point destroyed
How can I make it so that Point is only destroyed once?
You need to return by value instead of reference. Using
Point getPoint()
{
return { 100, 120 };
}
Allows C++17's guaranteed copy elision to kick in which causes Point p = getPoint(); to act as if it was Point p{ 100, 120 };
Side note: Never, Never, Never, return a function local object by reference. That object will be destroyed at the end of the function leaving you with a dangling reference and using that is undefined behavior.
Here's an example of what it looks like you're trying to achieve...
#include <iostream>
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
// Explicitly deleting the Copy Constructor only to illustrate a point.
Point(const Point& other) = delete;
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
int main() {
Point a = makePoint(3, 5);
std::cout << a.x << ',' << a.y << '\n';
}
Output:
3,5
Destructor called
If you noticed, I explicitly deleted the Copy Constructor and left the Assignment Operator undeclared so that it will use the default. The struct is still using the default constructor and I didn't define a User Defined constructor.
In makePoint() I added two parameters/arguments to the function so that the user can set any values to the Point object. The function is returning a const Type object. The return statement in the function is using:
return Point{a, b};
instead of
return Point(a, b);
The latter will fail to compile because there is no user-defined constructor. However, the former works because I'm using brace-initialization. This will allow construction of the object on return instead of creating a temporary on the stack frame of the function and copying that temporary as its return value. This is a form of Copy Elision.
Now, if you want to be able to copy this object, you can remove the deleted constructor and allow the class to use its default copy constructor. The semantics of the Copy Elision will still work.
This will have the same exact results. I showed the explicit deletion of the Copy Constructor to initially prevent any Copying semantics. Then explained how the code works so you can take the original above and remove the line for the deleted copy constructor and it will still work the same:
struct Point {
size_t x;
size_t y;
~Point() { std::cout << "Destructor called\n"; }
};
const Point makePoint(size_t a, size_t b) {
return Point{ a, b };
}
The functionality or behind the scenes magic is happening within the function makePoint() and that it returns a const object and uses brace-initialization of the class.
I want to know is it okay if i will use following method? There is no syntax errors and any warnings but i want to know is there any memory problems?
#include <iostream>
using namespace std;
class test {
int* x;
public:
test(int *n) { this->x = new int(*n); }
inline int get() { return *x; }
~test() { delete x; }
};
int main(void) {
while(1){
test a(new int(3));
cout << a.get() << endl;
}
return 0;
}
You have 2 issues in your code:
your class violates rule of three/five/zero
you are leaking memory when create a
In this code:
test a(new int(3));
you dynamically allocate int with value 3 and pass to a ctor which uses value and creates it's own dynamically allocated int. After that this memory is leaked. If you want to pass dynamically allocated data to a class use a smart pointer:
class test {
std::unique_ptr<int> x;
public:
test(std::unique_ptr<int> n) : x( std::move( n ) ) { }
int get() const { return *x; }
};
int main()
{
x a( std::make_unique<int>( 3 ) ); // since c++14
x a( std::unique_ptr<int>( new int(3) ) ); // before c++14
...
}
and you do not need to implement dtor explicitly, you do not violate the rule and it is safe to pass dynamically allocated data to ctor.
Note: I assumed you used int as example and you would understand that dynamically allocate one int is useless, you should just store it by value.
You are violating the rule of 3 (5 since c++11). It means that since you defined the destructor you should define the copy/move constructor/operation.
With your implementation, the copy/move constructor/operation are wrong. When you copy your object, it will do a shallow copy of your pointer and will delete it therefore you will have a double delete. When you move it, you will delete a pointer you didn't allocated.
Bonus point: your inline is useless
#include <iostream>
class Object {
public:
int x;
Object() { }
Object(int x) {
this->x = x;
}
};
class SomeClass {
public:
Object array[10];
int n;
SomeClass() { n = 0; }
void insert(Object o) {
array[n++] = o;
}
};
int main() {
SomeClass s;
Object test = Object(4);
s.insert(test);
return 0;
}
I have this example where I pre-allocate an array of objects in SomeClass and then in some other method, main in this example, I create another object and add it to the array in SomeClass
One thing I think I should do is to switch from array[10] to an array of pointers so that I only create objects when I really need to.
But my question is what happens to the memory originally allocated for array[0] when I do "array[n++] = o" replacing it by the new object "o"? does it get de-allocated?
No, nothing happens. The object's assignment operator gets invoked, to replace the object.
For this simple class, the assignment operator is the default operator which, more or less, copies each of the object's members, one at a time.
(No need to get into move operators, etc..., just yet)
I'm trying to understand Deep Copy. But I'm just confused about allocating dynamically memory by calling Constructor.
Here is my successful program for Deep copy:
#include<iostream>
using namespace std;
class A{
public:
int *p;
A(){
p=new int;
}
void set(int b){
*p=b;
}
int get(){
return *p;
}
void operator=(const A &k){
p = new int;
*p=*(k.p);
}
~A(){
delete p;
}
};
int main()
{
A obj;
obj.set(3);
A obj1;
obj1=obj;
obj1.set(5);
cout << obj.get() << endl;
cout << obj1.get() << endl;
}
Now I just want to ask that I created two objects and constructor will call for two times and in constructor there dynamically memory is allocating.
Then My Question is that pointer should point two different dynamically memory location(2 object and 2 pointer) or is pointer same as Static data members(then no deep copy should require)? Mean one pointer for all objects of class.
If you create two instances of that class, they will have two different p members each containing a different address of different regions in memory, yes.
You can probably tell if you run your program: it will display 3 and 5, if the pointer was the same, it would have displayed 5 twice.
Edit: as asked, some additional explanation (and a summary of what have been said in the comments)
First of all, your operator= is leaking memory, instead you should remember to release the memory already allocated in p before reassigning it:
void operator=(const A &k){
delete p;
// as JoshuaGreen states in the comments, you can set p to nullptr
// here, that way, if new fails and throws, p will be set to nullptr
// and you'll know it doesn't contain anything (you'll have to test
// it in other methods to benefit from this modification though,
// but it will be safer)
p = nullptr;
p = new int;
*p=*(k.p);
}
Although in this specific case, you could just avoid reallocating:
void operator=(const A &k){
// p = new int; // not needed
*p=*(k.p);
}
Now, that was indeed important to overload the assignment operator= (and you actually forgot to overload the copy constructor), let's see what would have happened if this assignment operator= wasn't defined.
Your class would instead look like this:
#include<iostream>
using namespace std;
class A{
public:
int *p;
A(){
p=new int;
}
void set(int b){
*p=b;
}
int get(){
return *p;
}
~A(){
delete p;
}
};
But actually, the compiler will generate an implicitly defined default copy constructor and default assignment operator= for you. Of course you don't see their implementation, but they would behave exactly the same as if the class was defined like this:
#include<iostream>
using namespace std;
class A{
public:
int *p;
A(){
p=new int;
}
A(const A& other) :
p(other.p) {} // ! we're copying the pointer instead of reallocating memory
void set(int b){
*p=b;
}
int get(){
return *p;
}
A& operator=(const A& other){
p = other.p; // same here!
}
~A(){
delete p;
}
};
When you're class deals with dynamically allocated memory, that's bad. Let's see what would happen in your main:
int main()
{
// allocate a new pointer to int, let's call it p
A obj;
// set the content of p to 3
obj.set(3);
// allocate a new pointer to int, let's call it p1
A obj1;
// /!\
// instead of copying the content of p to the content of p1, we're
// actually doing p1 = p here! we're leaking memory AND the two
// objects point on the same memory!
obj1=obj;
// set the content of p1 to 5, but p1 is now equal to p because of
// the bad assignment, so we're also setting p's content to 5
obj1.set(5);
// print the content of p (5)
cout << obj.get() << endl;
// print the content of p1 (5)
cout << obj1.get() << endl;
}
// delete the contents of p and p1 /!\ we're actually deleting the same
// allocated memory twice! that's bad
That's why you have to redefine the "big three" (copy constructor, copy assignment operator, and destructor)
When pointers point to something declared in the same class, am I right in thinking that if you copy such an object that there are multiple sets of pointers but they all point to the same object(s)?
Does this mean there are other objects in the other class instances that have been created but that nothing is pointing to?
And as a side question, would I be right in thinking that a shared pointer would point all the classes at ONE set of objects but in a safe way?
yes - when you don't define a copy constructor the compiler will issue one for you - which will do a shallow copy - just copy the values(i.e the address) of the pointers.
So the two objects(original and 'copy') will have pointer fields pointing at the same object.
If you don't deep copy the object i.e. if you don't override the copy c'tor and do a shallow copy, the pointer(s) will point to the same instance of an object. If you then delete one of the shallow - copied objects then the pointers of the other objects will point to garbage. If you dereference them in any way your program will crash.
Same thing can happen with the assignment operator. So when you have pointers overload them both.
An example:
struct Message
{
Message(const LogType_E & type_in = LOG_ERROR, const unsigned int & domain_in = 0, const int & msgId_in = 0, const char * msg_in = "");
int myMsgID; //!< message id
unsigned int myDomain; //!< message domain
LogType_E myType; //!< message type
char * myMsg; //!< actual message
~Message()
{
if(myMsg != NULL) delete [] myMsg;
}
Message(const Message &);
const Message& operator=(const Message & rhs);
};
This is a "message" type used to hold a message with other thingies.
Implementation would look like :
Message::Message(const Message & cp_in):myType(cp_in.myType), myDomain(cp_in.myDomain), myMsgID(cp_in.myMsgID), myMsg(NULL)
{
if(cp_in.myMsg != NULL)
{
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
}
const Message & Message::operator =(const AX::Base::Log::Message &cp_in)
{
if (this == &cp_in) // protect against invalid self-assignment
return *this;
//deallocate old memory
if(myMsg != NULL) delete [] myMsg;
if(cp_in.myMsg != NULL)
{
//allocate new memory and copy the elements
myMsg = new char[strlen(cp_in.myMsg)+1];
memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1);
}
// copy other data members
myType = cp_in.myType;
myDomain = cp_in.myDomain;
myMsgID = cp_in.myMsgID;
return *this;
}
That said, please use std::string to avoid all these things - that was just a proof of concept example.
Imagine you have a class like so that exhibits the problem you have asked in the question
class Foo{};
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
};
And code like so
Bar x ;
Bar y = x;
The above code will cause an core dump because both y and x will point to the same Foo and the destructor will try to delete the same Foo twice.
ALTERNATIVE 1
Declare but not provide a definition so that Bar is never copy constructor or assigned. The will ensure that Bar y = x will have a link error as you have designed the class not be copied.
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar &);
Bar& operator= (const Bar &);
};
ALTERNATIVE 2
Provide a copy constructor and assignment operator that do the right thing. Instead of the compiler provided default implementation of copy and assignment that do shallow copy you are duplicating Foo so that both x and y have their own Foo
class Bar
{
public:
Foo* mFoo;
Bar() : mFoo( new Foo() ) {}
~Bar() { delete mFoo;}
Bar(const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
}
Bar& operator= (const Bar & src)
{
mFoo = new Foo( *(src.mFoo) );
return *this;
}
};
ALTERNATIVE 3 (BEST)
Use C++11 shared_ptr or boost and omit the copy and assigment as the default compiler provided one will do the right thing as shared_ptr is ref counted and will delete Foo only once even though both x and y share the same Foo. Also notice that ~Bar needs to no explicit clean up as mFoo will automatically be deleted in std::shared_ptr<Foo> destructor when the the refcount of Foo becomes zero.
class Bar
{
public:
std::shared_ptr<Foo> mFoo;
Bar() :mFoo( new Foo() ) {}
~Bar() { }
};
Let the code do the talking to clear things up:
struct X
{
int data;
int *ptr;
X() : ptr(&data) {}
};
X a;
X b = a; // yes, `a.ptr` points to `b.data`!
Indeed, the pointers will be copied verbatim and will keep pointing into the source of the copy.
Use pointer-to-members
Fixable thus:
struct X
{
int data;
int X::*ptr;
X() : ptr(&X::data) {}
};
X a;
X b = a; // now, `a.ptr` points to `a.data`
Extending this sample with some more usage hints https://ideone.com/F0rC3
a.ptr = &X::data2; // now `a.ptr` points to `a.data2`
// `b.ptr` points to `b.data1`
b = a; // `b.ptr` points to `b.data2` too
// Usage hint:
int deref = a.*(a.ptr); // gets the field pointed to by a.ptr, from the instance a
deref = b.*(b.ptr); // gets the field pointed to by b.ptr, from the instance b
// but of course you could get fancy and do
deref = a.*(b.ptr); // gets the field pointed to by b.ptr, **but** from the instance a
That would do what you probably want. Although, why you want that is beyond me (and beyond C++, possibly)