0

Here is a Template class I've made to catch up on templates

template <typename T>
class Myclass {
    std::vector<T> v;    
public:
Myclass(): v({0}){;}
Myclass(const Myclass& M)
{
    this->v={1,2}; //ignore this I'm gonna use int for testing 
}
~Myclass()
{
    std::cout<<"Destructor";
}
void setter(T i)
{
    v.push_back(i);
}
auto getter() -> decltype(T)
{
     return v.back();
}
};

I would like to have the getter function return the last element in v and pop_back(). Now I could store the back() value in a variable and just pop_back(). But I was hoping I could come up with smart pointers to do the same. Here's what I came up with

auto getter() -> decltype(v.back())
{
    std::unique_ptr<T> p1 (new T);
    *p1=v.back();
    v.pop_back();
    return *p1;
}

and my main is

Myclass<int> m1;
m1.setter(5);
Myclass<int> m2=m1;
std::cout<<m1.getter()<<m1.getter()<<std::endl;
std::cout<<m2.getter()<<m2.getter()<<m2.getter();

Yeah I want to do it with local smart pointers so that I can "be sure" of the objects destruction. Now My program compiles but runs endless.

  • 1
    The smart idea here is even worse. –  Feb 08 '14 at 22:47
  • 1
    Calling `getter` three times inside the same statement is probably not a good idea. The order of evaluation is unspecified, so you could get them in any of the 6 possible orders. – fredoverflow Feb 08 '14 at 22:51
  • @FredOverflow: I am not sure that applies here. The multiple cout << would translate to cout.operator< – Enrico Granata Feb 08 '14 at 22:52
  • 2
    @EnricoGranata Oh, the **operators** are definitely executed from left to right, but the **operands** can be evaluated in any order. See [this question](http://stackoverflow.com/questions/2129230/), for example. – fredoverflow Feb 08 '14 at 22:55
  • @FredOverflow: you gotta love C++ so much.... ;) – Enrico Granata Feb 08 '14 at 23:04
  • @EnricoGranata It's more of a love-hate relationship, really... – fredoverflow Feb 08 '14 at 23:04
  • 1
    @FredOverflow: I meant more to say "C++ always has a new reason to deserve love" than "you personally love C++ a lot" to be honest.. but yeah love-hate is a good way to describe it – Enrico Granata Feb 08 '14 at 23:10
  • Hey I updated the problem –  Feb 08 '14 at 23:48
  • Getter is supposed to pop the vector too. so I don't see how it being called 3 times could be a problem. –  Feb 08 '14 at 23:49
  • @user3145076 The problem is that in `std::cout << f() << g() << h()`, there is no way to predict in which order the functions `f()`, `g()` and `h()` are going to be called. Again, see [this question](http://stackoverflow.com/questions/2129230/) for details. – fredoverflow Feb 09 '14 at 10:12

1 Answers1

2

No need for heap allocation, just use a good old local variable:

T getter()
{
    T temp = std::move(v.back());
    v.pop_back();
    return temp;
}
fredoverflow
  • 237,063
  • 85
  • 359
  • 638
  • +1, No need for `-> decltype(T)` either (as the code above shows). – Shoe Feb 08 '14 at 22:55
  • @6502 There is no copy construction, only move construction. Assuming `T` has a move constructor, of course ;) – fredoverflow Feb 08 '14 at 22:59
  • The problem is that if T has no move constructor and the copy construction throws at `return` point you get an exception but the value has been already removed from the vector and is lost. This IIRC was one of the reasons for which there is no `pop` (removing and returning) in C++ ... it's simply impossible to write correctly. – 6502 Feb 08 '14 at 23:03
  • @6502 You did well in C++ history class! That's exactly why. – fredoverflow Feb 08 '14 at 23:03
  • @6505 Thanks I always tried some generic implementation of it and never got it 100% exception free. –  Feb 08 '14 at 23:52