José Mari
José Mari

Reputation: 115

Issue when passing std::function as a parameter

I'm having this strange issue (I've simplified the code here) with clang 3.1 (gcc works fine). Is it improper use of std::function (passed by value) or a clang bug?

template <typename Container>
struct A
{
  using function_type = std::function<char(char)>;

  A(Container c, function_type f) : it_(c.begin()), f_(f) {}
  typename Container::value_type operator*() { return *it_; }

  typename Container::iterator it_;
  function_type f_;
};

template <typename Cont>
A<Cont> makeA(Cont c, std::function<char(char)> f)
{
  return A<Cont>(c, f);
}

char f(char ch) { return ch; }

int main()
{
  std::string s { "foo" };
  auto a = makeA(s, f); // wraps s.begin()
  std::clog << "main: " << *(s.begin()) << std::endl; // prints 'f'
  std::clog << "main: " << *a << std::endl; // prints garbage
  return 0;
}

I'm using Apple clang 4.1 (llvm 3.1) on Max OS X Lion.

If I change the type of the second parameter to something else (such as int), everything works fine.

If I construct the A object directly from the ctor, instead of using the 'make' factory, everything works fine.

I really can't understand whether it's a clang bug or my misunderstanding.

Upvotes: 2

Views: 320

Answers (1)

Mankarse
Mankarse

Reputation: 40633

You are passing the string by value in to the constructor of A, and then creating an iterator in to the local string. The string is then destroyed at the end of the constructor, leaving you with an invalid iterator and undefined behavior.

//`c` is a local copy of the string
A(Container c, function_type f) :
    //c.begin() returns an iterator into `c`
    it_(c.begin()),
    f_(f)
{
}//`c` is destroyed, leaving it_ as a dangling iterator

//Dereferences `it_` -- undefined behaviour
typename Container::value_type operator*() { return *it_; }

Upvotes: 6

Related Questions