Reference to dynamic object

I'm still working on a space shooter engine. All entities need to be stored in the dynamic memory. I managed to force this by making the constructor private and by adding a static method which dynamically creates an object and returns a pointer. Edit: as LB says in the next post, I don't need to force this. But it is most likely that the user will want to make them dynamically and we still have the following problem. It means the user has to do this...

1
2
3
4
entity* player = entity::create();
(*player).setPosition(something);
(*player).act();
(*player).draw();

You get the point, having to dereference the pointer before each call becomes painful. So I thought about this... Instead of returning a pointer, I can return a reference. Then the code is much cleaner.

1
2
3
4
5
6
7
8
9
{
    entity& test = entity::create();

    // do stuff...
    test.act();
    // more stuff...

    test.destroy(); // deletes the dynamic object
}

I put this code between brackets. That's because we must make sure the reference test doesn't exist after destroy is called, because destroy() makes it invalid. This is fully functional and won't cause any problem as long as the user doesn't forget to never call any method on a destroyed entity. But it's evil code. Would you risk it, or is there another way around?
Last edited on
pivottt wrote:
All entities need to be stored in the dynamic memory. I managed to force this by making the constructor private and by adding a static method which dynamically creates an object and returns a pointer.
What? Why would you do this? There is no reason to try and 'force' the use of dynamic memory here - just use dynamic memory naturally.
It's true, it doesn't really matter if I allow non-dynamic creation or not. I could just leave the constructor public in case someone wants to create an entity for the duration of a function.

But I still have the same ugly syntax problem if the user just does entity* test = new entity(); which is going to be the most common situation. Every method call is going to require (*nameofpointer).nameofmethod();

This is what I'm trying to avoid. But I guess it's better to have ugly syntax then invalid references.
Last edited on
Have you ever heard of the -> operator?

nameofpointer->nameofmemberfunction();
Last edited on
Facepalm. I used it a lot when creating containers, but I hadn't thought about using it on methods. Now that you mention it, this is exactly how SDL works. You declare your images dynamically and you call methods using the arrow operator.

Well, guess this means no more programming pas 11pm. Thanks and sorry for the loss of time :)
> I managed to force this by making the constructor private
> and by adding a static method which dynamically creates an object
> user doesn't forget to never call any method on a destroyed entity.
> But it's evil code. Would you risk it, or is there another way around?

Provide a wrapper which exposes simple value semantics. Something like this:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <memory>
#include <utility>
#include <string>

struct A_impl // only dynamic storage duration is supported
{
    using pointer = std::unique_ptr<A_impl> ;

    // for exposition only
    // assume that we have a good reason to enforce creation via factory function
    // for instance: A_impl is a flyweight
    //               A_impl needs to be placed into non-pageable memory
    //               etc.
    template< typename... ARGS > static pointer make( ARGS&&... args )
    { return pointer( new A_impl( std::forward<ARGS>(args)... ) ) ; }

    int value() const { return value_ ; }
    std::string name() const { return name_ ; }
    // ...

    A_impl& operator= ( const A_impl& ) = default ;
    A_impl& operator= ( A_impl&& ) = default ;

    private:
        int value_ = 8 ;
        std::string name_ ;

        A_impl() = default ;
        explicit A_impl( int v ) : value_(v) {}
        A_impl( int v, std::string& s ) : value_(v), name_(s) {}
        A_impl( int v, std::string&& s ) noexcept : value_(v), name_( std::move(s) ) {}
        A_impl( const A_impl& ) = default ;
        A_impl( A_impl&& ) noexcept = default ;
};

struct A // syntactic sugar
{
    template< typename... ARGS >
    explicit A( ARGS&&... args ) : impl( A_impl::make( std::forward<ARGS>(args)... ) ) {}

    // copy is a deep copy
    A( A& that ) : impl( A_impl::make( that.value(), that.name() ) ) {}
    A( const A& that ) : impl( A_impl::make( that.value(), that.name() ) ) {}

    // move is normal move
    A( A&& that ) noexcept = default ;

    // likewise for operator =

    int value() const { return impl->value() ; }
    std::string name() const { return impl->name() ; }
    // ...

    private: A_impl::pointer impl ;
};

A foo() { return A( 23, "abcd" ) ; }

int main()
{
    A a( 17, "hello" ) ;
    std::cout << a.value() << ' ' << a.name() << '\n' ;

    A copy_of_a(a) ;
    std::cout << copy_of_a.value() << ' ' << copy_of_a.name() << '\n' ;

    A moved_to( foo() ) ; // move construct from prvalue
    std::cout << moved_to.value() << ' ' << moved_to.name() << '\n' ;
}

http://coliru.stacked-crooked.com/a/28124e3d05522f72
Wow. I'll need some time to read about half the containers and keywords used here, but I get the general idea and it's very nice! Thanks!
Topic archived. No new replies allowed.