My code works as is, but how do I use the constructor?

Here is my code so far:

megatron.h - In namespace megatron::utility

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T>
class megaptr
{
private:
	T* object;
public:
	megaptr()
	{
		object = new T;
	}
	~megaptr() { delete object; }
	T& operator() ()
	{
		return *object;
	}
};


main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class AnObject
{
private:
        int var;
public:
	AnObject() { var = 0;}
	AnObject(int i) { var = i; }
	~AnObject() {}
	int& GetVar() { return var; }
};

int main()
{
        megatron::utility::megaptr<AnObject> MyObject;
        std::cout << MyObject().GetVar() << "\n";
        return 0;
}



The code works ( It seems anyway ) but I am unable to use the object constructor. I think I know where the problem is:

1
2
object = new T;
// I need something like - object = new T(...); 


I need to be able to the find if a constructor is used and be able to create the object from it's constructor as well as it's default, any ideas?

Thanks in advance,
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
#include <utility>
#include <iostream>
#include <string>

template < typename T > struct megaptr
{
    // http://en.cppreference.com/w/cpp/utility/forward
    template< typename... CONSTRUCTOR_ARGS > megaptr( CONSTRUCTOR_ARGS&&... args )
        : ptr( new T( std::forward<CONSTRUCTOR_ARGS>(args)... ) ) {}

    T& operator*() { return *ptr ; }
    T* operator-> () { return &**this ; }

    // ...

    private: T* ptr ;
};

int main()
{
    megaptr<std::string> p1, p2( "hello world!" ), p3( 23, '!' ) ;
    std::cout << '\'' << *p1 << "'    size: " << p1->size() << '\n'
              << '\'' << *p2 << "'    size: " << p2->size() << '\n'
              << '\'' << *p3 << "'    size: " << p3->size() << '\n' ;
}

http://coliru.stacked-crooked.com/a/bce447e1989743ab
I am really struggling understanding this part of the code:

1
2
 template< typename... CONSTRUCTOR_ARGS > megaptr( CONSTRUCTOR_ARGS&&... args )
 : ptr( new T( std::forward<CONSTRUCTOR_ARGS>(args)... ) ) {}


My first query is:

1
2
 
template< typename... CONSTRUCTOR_ARGS > megaptr( CONSTRUCTOR_ARGS&&... args )


Are you redefining the original template? Or is this a new template function for megaptr? Because in main you only use the one template parameter <std::string> but two templates are defined?

Sorry I'm new to this template stuff.

Also I'm not entirely sure about CONSTRUCTOR_ARGS&& ( I think move? ) and &** on line 17.
You have not provided a way for megaptr to accept an argument object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <class T>
class megaptr
{
private:
	T* object;
public:
	megaptr()
	{
		object = new T;
	}
        
        megaptr( T* object ): 
        object( object ) 
        { 
        }
        
	~megaptr() { delete object; }
	T& operator() ()
	{
		return *object;
	}
};

Now you can use it with stuff you specifically allocate:

12
13
14
15
16
17
int main()
{
        megatron::utility::megaptr<AnObject> MyObject = new AnObject( -7 );
        std::cout << MyObject().GetVar() << "\n";
        return 0;
}

Hoep this helps.
@Duaos

I should chop my right hand off for missing that, but I'll settle for saying thanks for pointing that out.

However I have implemented JLBorges approach, after some time I understand I think, how it works now and I am comfortable with implementing it elsewhere.

What advantages does the template code have over the constructor approach?


And another question, is this useless code? I'm guessing using this has no advantages over using a normal object.
Funny how slow I can be sometimes. I considered giving the packed template response, but it is a bit more complicated where a simple additional constructor would do for your purpose.

That said, what's wrong with std::shared_ptr? It does everything you want, but better.
http://en.cppreference.com/w/cpp/memory/shared_ptr
Nothing is wrong with the standard and I know it will be better than what I can create. I'm just fiddling really, seeing what tools I can make myself to help better my programming, and hopefully on the path implement some of my own in to the standard, but I'm sure hell would freeze over before I get that chance. :)

What does a shareptr do? Silly question really, I assume it shares the pointer, I think how and why would be a better question.

What other things could I try to implement within this object? I think returning the pointer and allowing the allocation of numerous pointers. Could you think of anything? Maybe something that would test me further?
> Are you redefining the original template? Or is this a new template function for megaptr?
> Because in main you only use the one template parameter <std::string> but two templates are defined?

>> I think I understand the second template function now after re-writing it, I believe it's a template constructor
>> ( I didn't think you could do that :) and it seems as if the template makes an argument parameter pack
>> which is forwarded the constructor arguments. please let me know if I was close.

Your understanding is spot on.

Parameter packs: http://en.cppreference.com/w/cpp/language/parameter_pack

The construct T&& for some deduced type T is what Scott Meyers calls a 'universal reference'.
http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

Perfect forwarding: http://thbecker.net/articles/rvalue_references/section_01.html
The whole article is worth careful perusal; sections 7 and 8 are about perfect forwarding.


>>> And another question, is this useless code?

There may be (are) much better (correct, robust) alternatives available in the standard library; in practice one would a std::unique_ptr<> instead of a megatron::utility::megaptr<>.

But it is, emphatically, not useless code. While learning C++, any code (that we write ourselves) that teaches us something is the most useful kind of code we can write.


>>>> Maybe something that would test me further?

Consider: what would happen if a copy of a megaptr<> object was made?
When both the copy and the original are destroyed?

Then read up on std::unique_ptr<>
http://en.cppreference.com/w/cpp/memory/unique_ptr
http://www.devx.com/cplus/10MinuteSolution/39071
Last edited on
@JLBorges

You know if I had the money I'd strongly urge you to be my private tutor. Each one of your answers are precise both in theory and evidence. I cannot thank you enough for your help. It's SO quality.

I much appreciate your help with my goal instead of giving me the "Just use the standard", and I haven't forgot both you and Duoas helped me with my program piping.

Thank you both.

Niceties aside:

I will be sure to read the content on all those links, and I'll read up on shared and unique pointers, see how they work and attempt to implement my own.


I think you are 100% on that, any code which you learn from probably is the best code. There is always a nice feeling that comes with taking a step closer to understanding.

I will try to figure out that problem, I'm having a bit of trouble understanding:


When both the copy and the original are destroyed


By destroyed do you mean the object going out of scope? or the pointer has been deleted? I'm struggling to understand how something can be copied if both the objects are destroyed.
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
#include <utility>
#include <iostream>
#include <string>

template < typename T > struct megaptr
{
    template< typename... CONSTRUCTOR_ARGS > megaptr( CONSTRUCTOR_ARGS&&... args )
        : ptr( new T( std::forward<CONSTRUCTOR_ARGS>(args)... ) )
          { std::cout << "created object of type T at address " << ptr << '\n' ; }

     ~megaptr()
     {
         std::cout << "destroy object of type T at address " << ptr << '\n' ;
         // delete commented out to avoid double delete (undefined behavior)
         // delete ptr ;
     }

    T& operator*() { return *ptr ; }
    T* operator-> () { return &**this ; }

    // ...

    private: T* ptr ;
};

int main()
{
    megaptr<int> ptr_one(123) ;
    std::cout << "ptr_one created\n" ;

    {
        megaptr<int> ptr_two(5678) ; 
        std::cout << "ptr_two created\n" ;
        
        ptr_two = ptr_one ; // copy assignment
        // what happens to the object originally 'pointed to' by ptr_two?
        // what does ptr_two 'point to' after this assignment?
        
        std::cout << "about to destroy ptr_two\n" ; // life-time of ptr_two is almost over
    }   

    // what about the object that ptr_one 'pointer to'?

    std::cout << "about to destroy ptr_one\n" ; // life-time of ptr_one is almost over
}

clang++ -std=c++11 -stdlib=libc++ -O3 -Wall -Wextra -pedantic-errors -pthread main.cpp -lsupc++ && ./a.out
created object of type T at address 0xc33010
ptr_one created
created object of type T at address 0xc33030
ptr_two created
about to destroy ptr_two
destroy object of type T at address 0xc33010
about to destroy ptr_one
destroy object of type T at address 0xc33010

http://coliru.stacked-crooked.com/a/21a1a2c97e9c1e8f
The first thing that came to mind would be when overloading the = operator, I'd assign *ptr_two = *ptr_one instead of copying the address, but I guess that kinda defeats the purpose of a pointer?

My next thought would be including a static vector to the megaptr class and store all addresses used by megaptr objects, if more than one of the same address exists in the vector, the value is removed until one is left, in which the destructor would then free the memory. That seems more viable, it's a method I also use while debugging if I have missed a bracket somewhere.

Another thing I have just thought of would be including local head and tail pointers to addresses of other megaptr objects that have the same value address, when destructing if the megaptr is connected to one of the same pointed value, the destructor would assign it's "next in link" object address to the tail of the link before it, when no more links exists the object frees the memory.


These are just the ideas I've had, let me know if I'm in the right direction.
> My next thought would be including a static vector to the megaptr class and store all
> addresses used by megaptr objects, if more than one of the same address exists in
> the vector, the value is removed until one is left, in which the destructor would then free the memory.

> Another thing I have just thought of would be including local head and tail pointers to
> addresses of other megaptr objects that have the same value address, when
> destructing if the megaptr is connected to one of the same pointed value, the
> destructor would assign it's "next in link" object address to the tail of the link before
> it, when no more links exists the object frees the memory.

In this case, we are talking about a megaptr which implements 'shared ownership semantics'.
Many owing pointers (megaptrs) could 'point' to the same object; when the last megaptr which points to an object goes away, the object is destroyed.

Design concerns include:
What is an efficient way to maintain the count of how many megaptrs are 'pointing' to the same object;?
What happens if object A holds a megaptr that points to object B, and object B holds a megaptr that points back to object A?
...

(Note that destroying an object may be more involved more than just 'freeing the memory'; for instance the destructor may need to release other resources: close files, release database locks, relinquish the ownership of a mutex, ...)


A second approach could be to have megaptr implements 'exclusive ownership semantics'.
At a point in time, one and only one megaptr is allowed to 'point' to a particular object; when that megaptr goes away, the object is destroyed.

Design decisions:
Should we disallow copying of megaptrs altogether?
Or could we provide a mechanism by which a megaptr could somehow transfer its exclusive ownership to the copy which was made?
Is it possible to make megaptr be smart, and at the same time, as efficient as a raw pointer?
...


In both cases:
Could the smart pointer be a null pointer?
Should it be possible to compare two smart pointers for equality?
Should a smart pointer to a derived class object be implicitly convertible to a smart pointer to a base class object?
...

Think about these, as well as other concerns that will surface as you go along.
Topic archived. No new replies allowed.