Copy Constructor Not Functioning Properly

closed account (zb0S216C)
I have a copy constructor, declared explicit, that takes a reference to the same type, like a normal copy constructor. However, it's not behaving. I've placed debugging information (with the pre-processor) within the body of the copy constructor, but even that isn't printing.

Due to this behaviour, I have concerns regarding how the memory is copied, not transferred, from one class to another.

Here's my constructor:

1
2
3
4
5
6
7
8
9
10
11
    template <typename T>
    MemoryRegion<T>::MemoryRegion(const MemoryRegion<T> &Region)
        : Def_Size_(Region.Def_Size_),
          Bs_Ptr_(Region.Copy()),
          Lt_Ptr_((Bs_Ptr_) ? &Bs_Ptr_[(Def_Size_ - 1U)] : 0)
    {
        #if defined MEMORY_REGION_DEBUG_DEF
            std::cout << "DEBUG -> Region.Capacity: " << Region.Capacity() << '\n';
            std::cout << "DEBUG -> Capacity: " << this->Capacity() << '\n';
        #endif
    }

Here's a quick overview of what happens here: First, Def_Size_ attains the region size of Region. Then, Bs_Ptr_ is assigned to the pointer returned by Region.Copy() (MemoryRegion<T>::Copy() copies the region of the associated class and returns a pointer to it). Finally, Lt_Ptr_ is set to point to the last item within the region.

Before proceeding, note the destructor definition:

1
2
3
4
5
6
7
8
9
10
11
12
    template <typename T>
    MemoryRegion<T>::~MemoryRegion()
    {
        #if defined MEMORY_REGION_DEBUG_DEF
            if(!this->Bs_Ptr_)
                std::cout << "DEBUG -> Bs_Ptr_ doesn't require deletion" << '\n';

            else std::cout << "DEBUG -> Bs_Ptr_ requires deletion" << '\n';
        #endif

        delete [] this->Bs_Ptr_;
    }

Now, the output should be (or something similar to):

DEBUG -> Region.Capacity: 2048
DEBUG -> Capacity: 1024
DEBUG -> Bs_Ptr_ requires deletion

Here's the twist: There's no output, no thrown exceptions, no crashes - nothing, and I don't know why. MEMORY_REGION_DEBUG_DEF is definitely defined, by the way.

Thoughts?

P.S: Mind the makeshift debugging, and naming conventions.

Wazzak
Last edited on
Which code should be calling the copy constructor? Do you have optimizations turned off? This sounds like compiler optimization.

When did you get your old account back?
closed account (zb0S216C)
L B wrote:
Which code should be calling the copy constructor?

Oh, sorry, I forgot add that. Here's the call site:

 
MemoryRegion<int> FinalRegion(MemoryRegion<int>());

The call is only for testing, to see if the copy constructor does in fact work, and how it responds to different calls.

L B wrote:
This sounds like compiler optimization.

I never contemplated optimisations, to be honest. It's in debug mode, too, so optimisations are off.

L B wrote:
When did you get your old account back?

An hour or two ago. Feels good to be home :)

Thanks for your replay, LB.

Wazzak
Not even the deconstructor output is shown? (If it is shown, is it possible that it is NOT being copy constructed but move copy constructed, which would bypass your output debugging efforts )
closed account (zb0S216C)
clanmjc wrote:
Not even the deconstructor output is shown?

Nope. Nothing. Not even when FinalRegion leaves the scope of main(), which is worrying.

Update:

I invoked the copy constructor this way:

1
2
MemoryRegion<int> TempRegion(2048U);
MemoryRegion<int> FinalRegion(TempRegion);

The constructor actually printed something - and the right thing at that. So, it all boils down to why the previously defined call site (MemoryRegion<int> FinalRegion(MemoryRegion<int>());) doesn't work.

Wazzak
Last edited on
Even compilers with optimization turned off will optimize that; I just tried in VC++ with optimization explicitly off and I had to jump through a few hoops to get past the optimization.

Also, welcome home :)
Last edited on
Looks like an optimization to me (as already suggested by clanmjc)
To further my ideas, I think that that line you posted is being completely ignored (hence the lack of destructor calling)
I just tried it too, optimized away with optimizations off (doh!)
Get a derp-compiler that's too stupid to optimize anything at all :)
closed account (zb0S216C)
I'm using MinGW's latest release with all optimisations off. Here's the invocations I've made thus far:

1
2
3
4
5
6
7
8
9
10
11
12
// 1
MemoryRegion<int> FinalRegion(MemoryRegion<int>);

// 2
MemoryRegion<int> FinalRegion(MemoryRegion<int>());

// 3
MemoryRegion<int> FinalRegion(MemoryRegion<int>(1024U));

// 4
MemoryRegion<int> TempRegion;
MemoryRegion<int> FinalRegion(TempRegion);

Invocations 1 & 2 are both accepted, but even with all optimisations off, on both release & debug builds, but still prints nothing. The rest of the invocations, however, actually print something. I don't understand why the compiler would optimise away output, if in fact it is an optimisation issue.

L B wrote:
Also, welcome home :)

Thanks :)P

Wazzak
Last edited on
The problem with 1 and 2 is that A. you're not using the variable you created and B. the net effect is calling the default constructor. The compiler sees this and decides it's just far to stupid to not optimize out. With 3, you're giving it a value, so it assumes that maybe the constructor might do something important. Because you don't have optimizations on it doesn't convert it to the net effect code. With 4, it's plain and simple that you have optimizations off and the code isn't trivial enough to optimize without consent.

Note: the above is guesswork.
Last edited on
This is not an optimization. This is a classic C++ syntax gotcha known as "Most Vexing Parse"

MemoryRegion<int> FinalRegion(MemoryRegion<int>()); is a declaration of a function named "FinalRegion", not initialization of an object.

The function you're declaring returns an object of type MemoryRegion<int> and takes a single argument of type pointer to function that takes no arguments and returns MemoryRegion<int>.

demo: http://ideone.com/NormF

Last edited on
closed account (zb0S216C)
Now that you mention that, Cubbi, I tried treating FinalRegion as a function, and it said something like: Too few arguments. Ultimately, the compiler thinks FinalRegion is a function, and the only way to invoke MemoryRegion's copy constructor is through call site #4.

To all that assisted me: Thank you for your assistance. If not for you all, I'd be sitting here with my head in the ground like a carrot with no idea what's wrong.

Thanks again :)P

Wazzak
and the only way to invoke MemoryRegion's copy constructor is through call site #4.

If your goal is to avoid the MVP, you could
MemoryRegion<int> FinalRegion((MemoryRegion<int>()));
or
MemoryRegion<int> FinalRegion = MemoryRegion<int>();
or, with sufficient C++11,
MemoryRegion<int> FinalRegion{MemoryRegion<int>()};

although in all these cases, any reasonable compiler will skip the copy ctor and just call the default ctor to create FinalRegion.
Topic archived. No new replies allowed.