3

I'm trying to write own Smart Pointers (C++11) and stacks with one problem, that can be explained by next example:

#include <iostream>

template<typename T_Type>
class TestTemplateClass {
private:
    T_Type _state;

public:
    TestTemplateClass() : _state() {
        std::cout << "Default constructor" << std::endl;
    }

    TestTemplateClass(int inState) : _state(inState) {
        std::cout << "State constructor" << std::endl;
    }

    template<typename T_OtherType>
    TestTemplateClass(const TestTemplateClass<T_OtherType> &inValue) {
        std::cout << "Template-copy constructor" << std::endl;
    }

    template<typename T_OtherType>
    void operator = (const TestTemplateClass<T_OtherType> &inValue) {
        std::cout << "Operator" << std::endl;
    }

    ~TestTemplateClass() {
        std::cout << "Destructor" << std::endl;
    }
};

TestTemplateClass<int> createFunction() {
    return TestTemplateClass<int>();
}

int main() {
    TestTemplateClass<int> theReference = createFunction();
    std::cout << "Finished" << std::endl;
    return 0;
}

output:

Default constructor
Destructor
Destructor
Finished
Destructor

As you can see, there are to many destructors here. In my mind, it's some problem with interaction between copy elision and template-constructor, but I don't know what may be the reason of such bug. I tried to fix the problem by adding explicit copy-constructor and force compiler use my template-constructor:

// After TestTemplateClass(int inState), but it's not important
explicit TestTemplateClass(const OwnType &inValue) {
    std::cout << "Copy constructor" << std::endl;
}

got next output:

Default constructor
Template-copy constructor
Destructor
Template-copy constructor
Destructor
Finished
Destructor

Here all looks good, but it doesn't look like a clean solution. Are there better alternatives?

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 1
    What compiler are you using? Are you compiling in debug mode or with constructor elision disabled? I [can't repro with g++ nor clang](http://coliru.stacked-crooked.com/a/f745bc99d5e16077) – user703016 Mar 12 '15 at 07:52
  • Just run it in release mode – ixSci Mar 12 '15 at 07:53
  • 2
    There's no such thing as a copy constructor template because the standard says so. In your first example the implicitly defined copy constructor is being called to create intermediate copies. What compiler are you using that is so terrible at copy elision? Or are you compiling with some flag that disables elision? – Praetorian Mar 12 '15 at 07:56
  • I'm using g++ 4.6.2. Yes, that is - copy-constructor wasn't specified through template... And no, I don't. I didn't used flags. – vsemenyakin Mar 12 '15 at 19:34

2 Answers2

5

(N)RVO can never introduce a discrepancy between the number of constructor and destructor calls. It's designed to make that principally impossible.

The problem is with your code. According to the rules of the language, a constructor template is never used to produce a copy constructor. The copy constructor is never a template, period.

So your class template does not actually declare a copy constructor, hence the compiler generates the default one (which of course doesn't print anything). If you need any special processing in the copy constructor, you must always declare it manually. A template will never be used to instantiate one.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Yes, you are right!.. And I uderstude why.Thank you very much! – vsemenyakin Mar 12 '15 at 18:48
  • I removed an 'explicit' key-word before a copy-constructor and have had a correct output: Default constructor Copy constructor Destructor Copy constructor Destructor Finished Destructor – vsemenyakin Mar 12 '15 at 19:18
  • And about original problem... Smart pointers are template classes depended on three template arguments (e.i. ref) - type and strategies for owning memory and for accesing to it. To make a code less complex, I tried to create something like template-aliases: strong_ref and weak_ref with fixed Owning and Access template argument values. My version of g++ (4.6.2) doesn't support template aliases. So, I tried to simulate template aliases using inheritance (strong_ref : public ref) and lost some constructors in "parent" pointer. – vsemenyakin Mar 12 '15 at 19:30
  • @user3621739 If an answer solves your problem, you can mark it as accepted (max. one accepted answer per question) by clicking the green tick-mark. This marks the question as solved, and gives both you and the answerer some reputation. It's [the way SO works](http://stackoverflow.com/help/someone-answers). – Angew is no longer proud of SO Mar 12 '15 at 19:49
  • Oh, thank you for explanation.. I have not enough reputation for plus reputation, but I'll set question as answered. – vsemenyakin Mar 12 '15 at 23:08
2

Your experiment suggests there isn't a bug at all: the first version simply used the copy constructor which doesn't print anything, and the second version uses a different constructor instead because you effectively disabled it.

(it also looks like whatever compiler and options you're using doesn't do RVO)