1

Hi please take a look at this.

struct obj
{
    std::string _name;
    int _val;

    obj(const std::string& name_ , int val_) : _name(name_) , _val(val_)
    {
        std::cout << "Created - " << std::endl;
    }

    ~obj()
    {
        std::cout << "Deleted - " << std::endl;
    }

    obj operator *(const obj& obj_) const
    {
        return obj(_name , obj_._val * _val);
    }


    friend std::ostream& operator<< (std::ostream& out_, const obj& obj_)
    {
        out_ << " Name =  " << obj_._name << " | val = " << obj_._val << std::endl;
        return out_;
    }
};

template <typename T>
T square(T x)
{
    return x*x;
}


int main()
{
    obj a("a" , 5);
    std::cout << square(a);
}

The output when I run this is :

Created - 
Created - 
 Name =  a | val = 25
Deleted - 
Deleted - 
Deleted - 

I am wondering why there is a unbalanced number of creation and destruction ? I suspect that a temporary object is being created when the operator* is called, but shouldn't the temporary object call the constructor too? I can balance it if I put a std::cout << "created" with in operator*.

I am just wondering why operator* does not call the contructor as I am clearly creating a temporary object there ? Does the templates have anything to do with this? I don't think so. Any help in understanding what I am doing wrong will be great !

nnrales
  • 1,481
  • 1
  • 17
  • 26
  • You forgot to track the copy constructor. Also, you shouldn't start your variable names with underscores. – PaulMcKenzie Nov 25 '16 at 05:48
  • Do the default copy cons is being called in the operator * ? Okay. – nnrales Nov 25 '16 at 05:53
  • It is ok, but you want to know when temporaries are created, right? So the only way to know that is to write a copy constructor that outputs that it's being called. – PaulMcKenzie Nov 25 '16 at 05:54
  • @PaulMcKenzie Any reason why I should not use - . I am not being defensive, I just want to hear the reasoning. It helps me keep track of private variables and variable that are passed into the function, but I agree it looks a bit confusing, but I find it cool. :) – nnrales Nov 25 '16 at 05:55
  • How else are you going to know when the copy constructor is called? It isn't going to output anything until you step in and write the code to output a message. – PaulMcKenzie Nov 25 '16 at 05:56
  • @PaulMcKenzie Yeah will try it out. Thank you. If you make it an answer, I can mark it as result. Could you also reply to the underscore comment, I am writing cpp code on my own, I want to make sure I am doing what other cpp devs are doing. – nnrales Nov 25 '16 at 05:56
  • 1
    square(T x) calls copy constructor and you didn't track it. if you used square(T& x), then no temporary would be created in square(). There is trick if you want to find implicit construction of objects, try to make copy constructor private.. compiler would whine about each occurrence. In general you should know about "Rule of three" – Swift - Friday Pie Nov 25 '16 at 05:59
  • @Swift It there a reason, like a rule in the cpp standard for that to happen, that is if the references are passed in no copy constructor is called ? – nnrales Nov 25 '16 at 06:04
  • @Swift Also what do you mean by implicit constructor? Do you mean the default constructor ? Or something generated by the complier. If the object has more complex data types, then the compiler won't be able to produce a good constructor automatically right ? – nnrales Nov 25 '16 at 06:06
  • 1
    Implicit constructor is the constructor that the compiler writes for you in some circumstances. Default constructor is always generated, so yes, in this case, it's default constructor. – Swift - Friday Pie Nov 25 '16 at 06:09
  • 2
    @nnrales - You might want to look at this: [What are the rules about using an underscore in a C++ identifier?](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – Bo Persson Nov 25 '16 at 07:46
  • @BoPersson Thanks, I was just reading Microsoft documentation and they too recommend, not beginning variable names with _ – nnrales Nov 25 '16 at 08:37
  • This isn't the problem, but don't use `std::endl` unless you need the extra stuff that it does; `'\n'` ends a line. – Pete Becker Nov 25 '16 at 14:25

2 Answers2

3

You forgot to output when the copy constructor is invoked. Since obj is being returned by value in operator *, copies can occur (they can be elided by the compiler, but let's assume they're not).

obj(const obj& rhs) : _name(rhs._name), _val(rhs._val)
{
   std::cout << "copy constructor called" << std::endl;
}

This should give you a better picture of what's going on when you return obj by value.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
1

Code of this template

template <typename T> T square(T x)
{
         return x*x; 
}

passes argument by value. Passing by value means copying it. operator* passes its argument by reference, no new objects are created. reference is a syntax sugar for address of variable (like a pointer). No copy constructor was declared in code, so compiler created an implicit one.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42