I'm trying to overload operators. I notice that in doing long expression, the compiler makes temporaries and destroy them at the end of statement (after ;). However, as the expression gets longer or the object that is larger, memory gets occupied for no reason (not that I know of). What I want is to destroy them after used like this:
    Test m3 = m1 - m2*2 + 3*m1;
    /* Temporaries predicted from result, temporaries might 
    have different declarations like 'const Test temp = ...;'
    Test temp_m1 = m1*3;
    Test temp_m2 = m2*2;
    Test temp_m3 = m1 - temp_m2;
    Test m3 = temp_m3 + temp_m1;
    temp_m3.~Test();  //destroyed at the end of statement
    temp_m2.~Test();  //destroyed at the end of statement
    temp_m1.~Test();  //destroyed at the end of statement
           ||
           \/
    Test temp_m1 = m1*3;
    Test temp_m2 = m2*2;
    Test temp_m3 = m1 - temp_m2;
    temp_m2.~Test();  //destroyed after temp_m2 is used
    Test m3 = temp_m3 + temp_m1;
    temp_m3.~Test();  //destroyed after temp_m3 is used
    temp_m1.~Test();  //destroyed after temp_m1 is used
    */
I have tried inputing rvalue to operator overloading functions, but it is not working as temporaries are lvalue. I notice that temporaries are created through move constructor and could take advantage of that, but it is not ideal.
The question is:
- Is there any way to differentiate temporaries from normal variables?
- If not, is there other way to destroy them after used?
- Is there any purpose in destroying them at the end of statement?
Main:
#include <iostream>
#include <iomanip>
class Test {
public:
    Test(const Test& m);
    Test(unsigned int limit = 0, int value = 0);
    Test(Test&& m);
    ~Test();
    Test& operator=(const Test& m);
    Test& operator=(Test&& m);
    Test operator+(const Test& m) const;
    Test operator-(const Test& m) const;
    Test operator*(const int& scalar) const;
    friend std::ostream& operator<<(std::ostream& os, const Test& m);
    void reset();
    unsigned int limit_ = 0;
    std::unique_ptr<int[]> data_;
};
int main(){
    Test m2(2,2);
    Test m1(2,1);
    Test m3 = m1 - m2*2 + 3*m1;
    /* Temporaries predicted from result, temporaries might 
    have different declarations like 'const Test temp = ...;'
    Test temp_m1 = m1*3;
    Test temp_m2 = m2*2;
    Test temp_m3 = m1 - temp_m2;
    Test m3 = temp_m3 + temp_m1;
    temp_m3.~Test();
    temp_m2.~Test();
    temp_m1.~Test();
    */
    std::cout << "RESULT" << std::endl;
    std::cout << m1;
    std::cout << m2;
    std::cout << m3;
}
Result:
Constructor: [ 2     2    ]
Constructor: [ 1     1    ]
Multiplication operation:
Constructor: [ 0     0    ]
[ 1     1    ]
 * 3 = [ 3     3    ]
Move constructor: [ 3     3    ]   //temp_m1
Destructor: Empty
Multiplication operation:
Constructor: [ 0     0    ]
[ 2     2    ]
 * 2 = [ 4     4    ]
Move constructor: [ 4     4    ]   //temp_m2
Destructor: Empty
Subtraction operation:
Constructor: [ 0     0    ]
[ 1     1    ]
 - [ 4     4    ]
 = [ -3    -3   ]
Move constructor: [ -3    -3   ]   //temp_m3
Destructor: Empty
Addition operation:
Constructor: [ 0     0    ]
[ -3    -3   ]
 + [ 3     3    ]
 = [ 0     0    ]
Move constructor: [ 0     0    ]   //m3
Destructor: Empty
Destructor: [ -3    -3   ]   //temp_m3 destroyed at the end of statement
Destructor: [ 4     4    ]   //temp_m2 destroyed at the end of statement
Destructor: [ 3     3    ]   //temp_m1 destroyed at the end of statement
RESULT
[ 1     1    ]
[ 2     2    ]
[ 0     0    ]
Destructor: [ 0     0    ]
Destructor: [ 1     1    ]
Destructor: [ 2     2    ]
Process returned 0 (0x0)   execution time : 0.125 s
Implementation code:
Test::~Test(){
        std::cout << "Destructor: " << *this << std::endl;
        data_.reset();
}
Test::Test(Test&& m){  //Move constructor
    std::cout << "Move constructor: ";
    data_ = std::move(m.data_);
    limit_ = m.limit_;
    m.reset();
    std::cout << *this;
}
Test::Test(const Test& m){  //Copy constructor
    std::cout << "Copy constructor: ";
    data_ = std::make_unique<int[]>(m.limit_);
    limit_ = m.limit_;
    for(unsigned int i=0; i<limit_ ; ++i) data_[i] = m.data_[i];
    std::cout << *this;
}
Test::Test(unsigned int limit, int value){    //Constructor
    std::cout << "Constructor: ";
    data_ = std::make_unique<int[]>(limit);
    limit_ = limit;
    if(limit == 0) return;
    for(unsigned int i=0; i<limit ; ++i) data_[i] = value;
    std::cout << *this;
}
Test& Test::operator=(const Test& m){ //Copy assignment
    std::cout << "Copy assignment: ";
    Test local_m = m;
    limit_ = local_m.limit_;
    data_ = std::move(local_m.data_);
    std::cout << *this << std::endl;
    return *this;
}
Test& Test::operator=(Test&& m){  //Move assignment
    std::cout << "Move assignment: ";
    Test local_m = std::move(m);
    limit_ = local_m.limit_;
    data_ = std::move(local_m.data_);
    std::cout << *this << std::endl;
    return *this;
}
Test Test::operator+(const Test& m) const{ //Addition
    std::cout << std::endl<< "Addition operation: " <<std::endl;
    if( limit_ != m.limit_){
        std::cout << "Addition error: not same dimensions, return Empty" <<std::endl;
        return Test();
    }
    if( limit_ == 0){
        std::cout << "Addition warning: Empty, return Empty" <<std::endl;
        return Test();
    }
    Test result(limit_);
    for ( unsigned int i = 0; i < limit_; ++i ) result.data_[i] = data_[i] + m.data_[i];
    std::cout << *this << " + " << m << " = " << result;
    return result;
}
Test Test::operator-(const Test& m) const{ //Subtraction
    std::cout << std::endl<< "Subtraction operation: " <<std::endl;
    if( limit_ != m.limit_){
        std::cout << "Subtraction error: not same dimensions, return Empty" <<std::endl;
        return Test();
    }
    if( limit_ == 0){
        std::cout << "Subtraction warning: Empty, return Empty" <<std::endl;
        return Test();
    }
    Test result(limit_);
    for ( unsigned int i = 0; i < limit_; ++i ) result.data_[i] = data_[i] - m.data_[i];
    std::cout << *this << " - " << m << " = " << result;
    return result;
}
Test Test::operator*(const int& scalar) const{ //Multiplication
    std::cout << std::endl<< "Multiplication operation: " <<std::endl;
    if( limit_ == 0){
        std::cout << "Multiplication warning: Empty, return Empty" <<std::endl;
        return Test();
    }
    Test result(limit_);
    for ( unsigned int i = 0; i < limit_; ++i ) result.data_[i] = data_[i] * scalar;
    std::cout << *this << " * " << scalar << " = " << result;
    return result;
}
Test operator*(const int& scalar, const Test& m){ //Multiplication
    return m * scalar;
}
std::ostream& operator<<(std::ostream& os, const Test& m){  //Show
    unsigned int limit = m.limit_;
    if (limit == 0) return os << "Empty" << std::endl;
    os << "[";
    for ( unsigned int i = 0; i < limit; ++i ){
            os << " " << std::left << std::setw(5) << m.data_[i];
    }
    os << "]" << std::endl;
    return os ;
}
void Test::reset(){ //Reset
        limit_ = 0;
        data_.reset();
}
 
    