smart pointer

how do i use a auto_ptr instead of a simple pointer here;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class factory
 27 {
 28 private:
 29         static Invoice* ptr;
 30 public:
 31         factory(){cout<<"factory constructor"<<endl;}
 32         ~factory(){cout<<"factory destructor"<<endl;}
 33         static Invoice* getPtr(int);
 34 
 35 };
 36 
 37 Invoice* factory::ptr = NULL;//i want to use a auto_ptr instead
 38 
 39 Invoice* factory::getPtr(int type)
 40 {
 41         enum {smooth,rough};
 42         if(type == smooth)
 43         {
 44                 ptr = new derived1;
 45         }
 46         else if(type == rough)
 47         {
 48                 ptr = new derived2;
 49         }
 50         else
 51         {
 52                 return NULL;
 53         }
 54         return ptr;
 55 }
 56 
 57 int main()
 58 {
 59         Invoice *q;
 60         auto_ptr<Invoice> p(factory::getPtr(0));
 61         
 62                 p->print();
 63         q = factory::getPtr(1);
 64         if(q)
 65                 q->print();
 66         
 67         return 0;
 68 }  



What modifications shld i make? thanks ( I have not provided the base and derived class just for simplicity, oherwise understood}
Last edited on
http://cplusplus.com/reference/std/memory/auto_ptr/

I've never used auto_ptr, but it looks like all you need to do is return an auto_ptr<Invoice> from the factory::getPtr function instead of a Invoice* to get the functionality your looking for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 37 // Invoice* factory::ptr = NULL;//i want to use a auto_ptr instead
 38 
 39 auto_ptr<Invoice> factory::getPtr(int type)
 40 {
 41         enum {smooth,rough};
              Invoice *ptr = NULL; //could define the pointer in local scope 
 42         if(type == smooth)
 43         {
 44                 ptr = new derived1;
 45         }
 46         else if(type == rough)
 47         {
 48                 ptr = new derived2;
 49         }
 50         //else
 51         //{
 52         //       return NULL;
 53         //}
 54         return (auto_ptr)ptr;
 55 }
 56 
 57 int main()
 58 {
 59         Invoice *q;
 60         auto_ptr<Invoice> p(factory::getPtr(0));
 61         
 62                 p->print();
 63         q = factory::getPtr(1).get(); //get the actual pointer
 64         if(q)
 65                 q->print();
 66         
 67         return 0;
 68 }


Is this what you meen? (Again I would check this because I've never used auto_ptr before; I'm going by the above reference page.)
@mathhead200:
well there is a problem with the code above. At line 63 the destructor is also called. Hence q seems to be deallocated and at line 65 it seg faults.
thanks


Assuming I have a static pointer called ptr. I think it will be better to make it an autoptr as well like

auto_ptr<Invoice> factory::ptr;

The getptr method should return an autoptr;

So how then can i make the code a autoptr?
Last edited on
Your static pointer 'ptr' has no purpose here. You should get rid of it.

The solution is [almost] what Mathhead suggested. Just return an auto_ptr from the function. No need for the factory to keep a copy of that pointer (and in fact, if this is an auto_ptr, it can't keep a copy because auto_ptrs can't be copied).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::auto_ptr<Invoice> factory::getPtr(int type)
{
  switch(type)
  {
    case smooth:  return new derived1;
    case rough:   return new derived2;
  }
  return 0;
}

//..

int main()
{
  std::auto_ptr<Invoice> p = factory::getPtr(smooth);
  p->print();

  p = factory::getPtr(rough);
  p->print();
}



Note it also makes no sense to have that enum local to getPtr because code that calls getPtr needs to have access to it.
Last edited on
@Disch:
factory.cpp: In static member function âstatic std::auto_ptr<Invoice> factory::getPtr(int)â:
factory.cpp:46: error: conversion from âderived1*â to non-scalar type âstd::auto_ptr<Invoice>â requested// this is the return new derived1 
factory.cpp:50: error: conversion from âderived2*â to non-scalar type âstd::auto_ptr<Invoice>â requested// this is the return new derived2 
factory.cpp:53: error: conversion from âintâ to non-scalar type âstd::auto_ptr<Invoice>â requested//this is the return 0



1)And based on what i understood abt auto_ptr is that they can be copied but the copying source will be set to null and the copied destination will have the value.

2)Assuming the client in main() has a Invoice* q(not an auto ptr). Now will this work with the getptr method which return an aurto_ptr. How can this be dealt with, since I cant control how the client will program.


Thanks again in advance

Last edited on
closed account (3hM2Nwbp)
std::auto_ptr's constructor is explicit, try returning std::auto_ptr<Type>(raw_pointer_to_type)

*Edit - and std::auto_ptr<Type>() for a null-auto-ptr

Here's the doc on it http://cplusplus.com/reference/std/memory/auto_ptr/

C++0x adds more features like std::shared_ptr and all its friends from the boost library, so you'll have more flexibility when creating automagically managed systems.
Last edited on
Yeah sorry, forgot the ctor was explicit.

Revised:

1
2
3
4
5
6
7
8
9
10
std::auto_ptr<Invoice> factory::getPtr(int type)
{
  Invoice* p = 0;
  switch(type)
  {
    case smooth:  p = new derived1; break;
    case rough:   p = new derived2; break;
  }
  return std::auto_ptr<Invoice>(p);
}
now that works but what if
2)Assuming the client in main() has a Invoice* q(not an auto ptr). Now will this work with the getptr method which return an aurto_ptr. How can this be dealt with, since I cant control how the client will program.
closed account (3hM2Nwbp)
For the most part auto_ptrs can be used just like a raw pointer. operator* and operator-> are both overloaded.
factory.cpp:60: error: cannot convert âstd::auto_ptr<Invoice>â to âInvoice*â in assignment
factory.cpp:61: error: request for member âgetâ in âqâ, which is of non-class type âInvoice*â


1
2
3
4
5
Invoice *q;
 q = factory::getPtr(1);//line 60
 
 if(q.get())//line 61
   q->print();


closed account (3hM2Nwbp)
1
2
3
4
5
std::auto_ptr<Invoice> q = factory::getPtr(1);
if(q)
{
    q->print();
}


*Edit - If I'm understanding your client situation correctly, maybe it would be best for you to make a factory for automatic pointers and one for raw pointers leaving it up to the client to use them properly. You might even be able to use some template specialization to make the package a little prettier for your end-user.
Last edited on
Which means the client should be aware that the code uses an auto_ptr? Cos as i have mentioned a client could just do this by Invoice *ptr without actually a auto_ptr. There is no way arnd this?
closed account (3hM2Nwbp)
The client should definitely be aware that the code uses automatic memory management. The most obvious reason that springs to mind would be the client explicitly calling delete on a "managed" pointer. There might be a way around it, the other members of this site are a whole lot more resourceful than I am when it comes to sneaky C++ magic. :)
No, not easily anyway. The point (heh) of auto_ptr is so that clients know that "This pointer is managed, don't screw with it."

You could have your factory class store a list of the pointers it has given out and delete them all at the end of it's lifetime.
So since the client has to be aware , and the auto_ptr automatically calls the destructor, now how can i then release the memory at the destructor?
If you are returning at auto_ptr, you don't need to do anything, the auto_ptr will clean it up for you. You seem to be confusing how deletion/memory works. In the destructor, you delete memory your CLASS has allocated with new in the constructor; you don't need to worry about the memory your class takes up with automatic variables.
so does that mean that new derived1 and new derived2 will be automatically deallocated. If that is so why does the code calls my destructor. I mean destructor is called to destroy allocated memory for example and if auto_ptr destroys by itself, then seems like i dont need my own destructor.

Or it calls my destructor just in case I have allocated other sort of memory and now need to deallocate it so it calls my own destructor?
so does that mean that new derived1 and new derived2 will be automatically deallocated.


If you are using auto_ptr, yes.

If that is so why does the code calls my destructor. I mean destructor is called to destroy allocated memory for example and if auto_ptr destroys by itself, then seems like i dont need my own destructor.


Your destructor allows your class to clean up any memory your class allocated. This is different from the memory your class occupies as firedraco tried to explain.

If, for instance, you are allocating some memory in Invoice constructor, you would need to free it in your destructor. If you are not doing any memory management in this class, then you probably don't need to write a destructor at all.

Or it calls my destructor just in case I have allocated other sort of memory and now need to deallocate it so it calls my own destructor?


Basically yes.



Here's an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass
{
  int* ptr;

public:
  MyClass()
  {
    ptr = new int;
  }
};

int main()
{
  MyClass* p = new MyClass;  // this allocates memory for 'p', then calls the ctor
    // the ctor then allocates memory for 'ptr'

  delete p;  // this deletes the memory for 'p' but DOES NOT delete the memory for 'ptr'
  // so we have a memory leak
}


Since 'ptr' is never deleted you have a memory leak. To solve that, you would write a dtor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyClass
{
//...
  ~MyClass()
  {
    delete ptr;
  }
};


int main()
{
  // same as before...
  MyClass* p = new MyClass;  // this allocates memory for 'p', then calls the ctor
    // the ctor then allocates memory for 'ptr'

  // now, delete calls p's dtor, which delete's memory for 'ptr'
  //  then it deletes the memory for 'p'
  delete p;  // no more memory leaks!
}
Topic archived. No new replies allowed.