2

The following code

#include <vector>
#include <string>
#include <iostream>

std::string const& at(std::vector<std::string> const& n, int i)
{
    return n[i];
}

std::vector<std::string> mkvec()
{
    std::vector<std::string> n;
    n.push_back("kagami");
    n.push_back("misao");
    return n;
}

int main()
{
    std::string const& s = at(mkvec(), 0);
    std::cout << s << std::endl; // D'oh!
    return 0;
}

may lead to crash because the original vector is already destructed there. In C++ 2011 (c++0x) after rvalue-reference is introduced in, a deleted function declaration can be used to completely forbid calls to at if the vector argument is an rvalue

std::string const& at(std::vector<std::string>&&, int) = delete;

That looks good, but the following code still cause crash

int main()
{
    std::string const& s = mkvec()[0];
    std::cout << s << std::endl; // D'oh!
    return 0;
}

because calls to member function operator [] (size_type) const of an rvalue object is still allowed. Is there any way can I forbid this kind of calls?

FIX:

The examples above is not what I did in real projects. I just wonder if C++ 2011 support any member function qualifying like

class A {
    void func() rvalue; // Then a call on an rvalue object goes to this overload
    void func() const;
};

FIX:

It's great, but I think C++ standard goes too far at this feature. Anyway, I have following code compiled on clang++ 2.9

#include <cstdio>

struct A {
    A() {}

    void func() &
    {
        puts("a");
    }

    void func() &&
    {
        puts("b");
    }

    void func() const &
    {
        puts("c");
    }
};

int main()
{
    A().func();
    A a;
    a.func();
    A const b;
    b.func();
    return 0;
}

Thanks a lot!

neuront
  • 9,312
  • 5
  • 42
  • 71

2 Answers2

6

No, and you shouldn't. How am I to do std::cout << at(mkvec(), 0) << std::endl;, a perfectly reasonable thing, if you've banned me from using at() on temporaries?

Storing references to temporaries is just a problem C++ programmers have to deal with, unfortunately.


To answer your new question, yes, you can do this:

class A {
    void func() &; // lvalues go to this one
    void func() &&; // rvalues go to this one
};

A a;
a.func(); // first overload

A().func(); // second overload
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • I've always found this reference binding appalling. It must have been a good idea to begin with, and sure comes handy at times, but its potential of destruction is incredible and even careful code inspection may fail to detect it... :/ – Matthieu M. Apr 28 '11 at 06:36
  • Thanks for that hint, but I got compile errors on g++ 4.6.0. Can you tell me which compiler can deal with that? – neuront Apr 28 '11 at 07:41
  • If you make the `func` overloads public, recent builds of clang will handle this example. – Howard Hinnant Apr 28 '11 at 13:29
  • Sorry, I don't get it. `void func() &;`... I can guess the intention, but I think I missed a point in the standard here. Trailing `&` after a method definition...? I have to look that one up. Ok, I found it! Amazing... – towi Apr 28 '11 at 19:20
-1

Just an idea:

To disable copying constructor on the vector somehow.

vector ( const vector<T,Allocator>& x );

Implicit copying of arrays is not that good thing anyway. (wondering why STL authors decided to define such ctor at all)

It will fix problems like you've mentioned and as a bonus will force you to use more effective version of your function:

void mkvec(std::vector<std::string>& n)
{
    n.push_back("kagami");
    n.push_back("misao");
}
c-smile
  • 26,734
  • 7
  • 59
  • 86
  • 1
    Are you seriously suggesting he modifies his standard library to make vector non-copy-constructable? Or am I misreading you? Because that is the silliest suggestion I have ever heard. – Benjamin Lindley Apr 28 '11 at 03:33
  • 1
    Your version of `mkvec` isn't necessarily more efficient, lookup RVO. – GManNickG Apr 28 '11 at 04:17
  • The function `mkvec()` is perfectly fine, yes! Thanks to **Return-Value-Optimization**, and in C++0x even more, thanks to RValues, yes. Please yes, write code like this, it is RAII, concise, safe and fast. But, of course `string &s = mkvec()[0]` explodes, thats correct. You named it right `mk...` **makes** something. Don't get a ref on something you just *made* -- that is the issue. If you would have called it `getvec()`, *then* I would expect `string&s=getvec()[0]` to be ok. But `string&s=mkvec()[0]` is allowd to fail :-) – towi Apr 28 '11 at 19:16