Storing pointer to instance of class with type conversion operator

Discussion in 'C++' started by Whitney Kew, Dec 6, 2004.

  1. Whitney Kew

    Whitney Kew Guest

    Hello,

    I have a question regarding type conversion operators. Let's say I
    have a simple (nonsensical) class as follows:

    class MakeNewInt
    {
    private:
    int* _n;

    // By the way, because of the type conversion operator, a
    // compiler might not catch an accidental deletion of a
    // stack instance - i.e., "delete MakeNewInt(123)" - so,
    // add a private operator void*() declaration.
    operator void*();

    public:
    operator int*() const
    {
    return _n;
    }
    MakeNewInt(int n) : _n(new int(n)) {}
    ~MakeNewInt()
    {
    delete _n;
    }
    };

    Let's also say that I have a method as follows:

    void f(int* n)
    {
    int* q = n;
    // Can do other things with q...
    }

    If I then invoke f() in a main() as such....

    int main()
    {
    f(MakeNewInt(123)); // OK
    return 0;
    }

    ....everything is fine; inside f(), I can operate on the pointer q,
    knowing that the destructor of MakeNewInt() won't be called until I
    exit f().

    If, however, I invoke MakeNewInt and attempt to store the result in a
    local variable, as such....

    int main()
    {
    int* n = MakeNewInt(123); // n is garbage
    return 0;
    }

    ....the destructor of MakeNewInt() has already been called as soon as I
    reach the "return 0;" line, and thus the pointer n points to garbage.
    Is there anything I can do to allow a caller to use my MakeNewInt class
    in this fashion?

    Thanks!
    Whitney Kew
    Software Engineer
     
    Whitney Kew, Dec 6, 2004
    #1
    1. Advertising

  2. Whitney Kew wrote:
    > I have a question regarding type conversion operators. Let's say I
    > have a simple (nonsensical) class as follows:
    >
    > class MakeNewInt
    > {
    > private:
    > int* _n;
    >
    > // By the way, because of the type conversion operator, a
    > // compiler might not catch an accidental deletion of a
    > // stack instance - i.e., "delete MakeNewInt(123)" - so,
    > // add a private operator void*() declaration.
    > operator void*();
    >
    > public:
    > operator int*() const
    > {
    > return _n;
    > }
    > MakeNewInt(int n) : _n(new int(n)) {}
    > ~MakeNewInt()
    > {
    > delete _n;
    > }
    > };
    >
    > Let's also say that I have a method as follows:
    >
    > void f(int* n)
    > {
    > int* q = n;
    > // Can do other things with q...
    > }
    >
    > If I then invoke f() in a main() as such....
    >
    > int main()
    > {
    > f(MakeNewInt(123)); // OK
    > return 0;
    > }
    >
    > ...everything is fine; inside f(), I can operate on the pointer q,
    > knowing that the destructor of MakeNewInt() won't be called until I
    > exit f().
    >
    > If, however, I invoke MakeNewInt and attempt to store the result in a
    > local variable, as such....
    >
    > int main()
    > {
    > int* n = MakeNewInt(123); // n is garbage
    > return 0;
    > }
    >
    > ...the destructor of MakeNewInt() has already been called as soon as I
    > reach the "return 0;" line, and thus the pointer n points to garbage.
    > Is there anything I can do to allow a caller to use my MakeNewInt class
    > in this fashion?


    int * const & n = MakeNewInt(123);

    The object here is bound to a reference to const and shall exist for as
    long as the reference exists.

    V
     
    Victor Bazarov, Dec 6, 2004
    #2
    1. Advertising

  3. Whitney Kew

    Whitney Kew Guest

    Unfortunately, that doesn't work; n points to a pointer that points to
    garbage as soon as the statement completes. Plus, I don't want the
    caller to have to remember something like that, since I don't
    necessarily have control over what the caller writes. I was hoping
    that there was some way that I could modify the MakeNewInt class, while
    preserving the type conversion operator functionality, so that a caller
    could safely make the following call:
    int* n = MakeNewInt(123);

    Thanks,
    Whitney
     
    Whitney Kew, Dec 6, 2004
    #3
  4. Whitney Kew wrote:
    > Unfortunately, that doesn't work; n points to a pointer that points to
    > garbage as soon as the statement completes.


    Your compiler might be broken, then. Binding to a const reference should
    keep the temporary around well past the declaration statement, AFAIUI.

    Try

    int * const & n(MakeNewInt(123));

    although AFAIK it shouldn't make any difference.

    > Plus, I don't want the
    > caller to have to remember something like that, since I don't
    > necessarily have control over what the caller writes. I was hoping
    > that there was some way that I could modify the MakeNewInt class, while
    > preserving the type conversion operator functionality, so that a caller
    > could safely make the following call:
    > int* n = MakeNewInt(123);


    When is the object going to be destroyed, then? Something has to exist
    that defines the lifetime of that temporary. In C++ there are three
    different limits for a temporary lifetime. Generally it is the full
    expression. Then the initialisation (with which you're struggling). And
    then there's binding to a const reference. No matter what you do in your
    class, you won't be able to change how the language is specified.

    You might want to rethink the need for your users to do such a stupid
    thing as holding onto a pointer obtained from a temporary object.

    V
     
    Victor Bazarov, Dec 6, 2004
    #4
  5. Whitney Kew

    Whitney Kew Guest

    Hm, strange. I tried your suggestion of:

    int * const & n(MakeNewInt(123));

    .... and my compiler couldn't even build it.

    OK, let me ask another question: My intended use of this class is for
    the callers to use it as in the first case...

    f(MakeNewInt(123));

    .... Could I somehow prevent the user from using it in the second case;
    in other words, at compile time, prevent the user from storing a
    temporary object?

    Thanks much!
    Whitney
     
    Whitney Kew, Dec 6, 2004
    #5
  6. Whitney Kew

    Whitney Kew Guest

    Unfortunately, that doesn't work; n points to a pointer that points to
    garbage as soon as the statement completes. Plus, I don't want the
    caller to have to remember something like that, since I don't
    necessarily have control over what the caller writes. I was hoping
    that there was some way that I could modify the MakeNewInt class, while
    preserving the type conversion operator functionality, so that a caller
    could safely make the following call:
    int* n = MakeNewInt(123);

    Thanks,
    Whitney
     
    Whitney Kew, Dec 6, 2004
    #6
  7. Whitney Kew

    adbarnet Guest

    Do you need to hold on to the pointer in your creating class? If that is a
    requirement, then implement the pointer with reference counting, if it isn't
    a requirement, then make a static create method returning a std::auto_ptr
    (implicitly passing pointer ownership to the caller).

    ad


    "Whitney Kew" <> wrote in message
    news:...
    > Hello,
    >
    > I have a question regarding type conversion operators. Let's say I
    > have a simple (nonsensical) class as follows:
    >
    > class MakeNewInt
    > {
    > private:
    > int* _n;
    >
    > // By the way, because of the type conversion operator, a
    > // compiler might not catch an accidental deletion of a
    > // stack instance - i.e., "delete MakeNewInt(123)" - so,
    > // add a private operator void*() declaration.
    > operator void*();
    >
    > public:
    > operator int*() const
    > {
    > return _n;
    > }
    > MakeNewInt(int n) : _n(new int(n)) {}
    > ~MakeNewInt()
    > {
    > delete _n;
    > }
    > };
    >
    > Let's also say that I have a method as follows:
    >
    > void f(int* n)
    > {
    > int* q = n;
    > // Can do other things with q...
    > }
    >
    > If I then invoke f() in a main() as such....
    >
    > int main()
    > {
    > f(MakeNewInt(123)); // OK
    > return 0;
    > }
    >
    > ...everything is fine; inside f(), I can operate on the pointer q,
    > knowing that the destructor of MakeNewInt() won't be called until I
    > exit f().
    >
    > If, however, I invoke MakeNewInt and attempt to store the result in a
    > local variable, as such....
    >
    > int main()
    > {
    > int* n = MakeNewInt(123); // n is garbage
    > return 0;
    > }
    >
    > ...the destructor of MakeNewInt() has already been called as soon as I
    > reach the "return 0;" line, and thus the pointer n points to garbage.
    > Is there anything I can do to allow a caller to use my MakeNewInt class
    > in this fashion?
    >
    > Thanks!
    > Whitney Kew
    > Software Engineer
    >
     
    adbarnet, Dec 6, 2004
    #7
  8. Whitney Kew wrote:
    > Hm, strange. I tried your suggestion of:
    >
    > int * const & n(MakeNewInt(123));
    >
    > ... and my compiler couldn't even build it.
    >
    > OK, let me ask another question: My intended use of this class is for
    > the callers to use it as in the first case...
    >
    > f(MakeNewInt(123));
    >
    > ... Could I somehow prevent the user from using it in the second case;
    > in other words, at compile time, prevent the user from storing a
    > temporary object?


    No. Just like you can't prevent a memory leak in the case

    f(new int(123));

    (which is probably what you're trying to do). There are some things in
    the language that every programmer has to know, and it's not really our
    responsibility to provide fool-proof methods for avoiding them. If your
    users are so inclined to make such mistakes like holding onto invalid
    pointers, they should be programming in Java instead.

    V
     
    Victor Bazarov, Dec 6, 2004
    #8
  9. Whitney Kew

    adbarnet Guest

    There are smart pointer templates you should take a look at - search google,
    or look at the Boost or Loki libraries - one form (NoCopy Policy in Loki)
    disallows copy and assignment of the pointer variable - you are forced to
    use the pointer through an accessor of the containing object. There is no
    other way to access the underlying pointer.

    You could implement it yourself - but someone's already done it so why
    bother?


    "Whitney Kew" <> wrote in message
    news:...
    > Hm, strange. I tried your suggestion of:
    >
    > int * const & n(MakeNewInt(123));
    >
    > ... and my compiler couldn't even build it.
    >
    > OK, let me ask another question: My intended use of this class is for
    > the callers to use it as in the first case...
    >
    > f(MakeNewInt(123));
    >
    > ... Could I somehow prevent the user from using it in the second case;
    > in other words, at compile time, prevent the user from storing a
    > temporary object?
    >
    > Thanks much!
    > Whitney
    >
     
    adbarnet, Dec 6, 2004
    #9
  10. Whitney Kew

    David White Guest

    "Whitney Kew" <> wrote in message
    news:...
    > Hm, strange. I tried your suggestion of:
    >
    > int * const & n(MakeNewInt(123));
    >
    > ... and my compiler couldn't even build it.
    >
    > OK, let me ask another question: My intended use of this class is for
    > the callers to use it as in the first case...
    >
    > f(MakeNewInt(123));
    >
    > ... Could I somehow prevent the user from using it in the second case;
    > in other words, at compile time, prevent the user from storing a
    > temporary object?


    As far as the class's clients are concerned, what is the difference between
    the class you've defined and this one?

    class MakeNewInt
    {
    private:
    int _n;
    operator void*();
    public:
    operator int*() const
    {
    return &_n;
    }
    MakeNewInt(int n) : _n(n) {}
    };

    I can't see any difference between them except that your version requires a
    lot more work for no benefit (your version needs a copy constructor,
    assignment operator and destructor, but mine doesn't). If you agree that the
    use of 'new' in your version is redundant, what memory management benefits
    could it offer?

    DW
     
    David White, Dec 6, 2004
    #10
  11. Whitney Kew

    Whitney Kew Guest

    Thanks for the replies, everyone.... You're right, Victor, you've
    answered my question - I am trying to prevent a memory leak, which is
    why I need a destructor, so that I can call some cleanup code, but only
    after the function f() completes. Thanks for the sanity check.

    Whitney
     
    Whitney Kew, Dec 7, 2004
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sridhar R
    Replies:
    14
    Views:
    1,408
    =?iso-8859-1?Q?Fran=E7ois?= Pinard
    Feb 10, 2004
  2. toton
    Replies:
    11
    Views:
    712
    toton
    Oct 13, 2006
  3. Martin T.
    Replies:
    7
    Views:
    820
    Martin T.
    Mar 10, 2008
  4. lallous
    Replies:
    10
    Views:
    1,551
    lallous
    Oct 6, 2009
  5. Martin P. Hellwig
    Replies:
    1
    Views:
    377
    Martin P. Hellwig
    Mar 26, 2010
Loading...

Share This Page