this question에서 작업하면서 GCC (v4.7)의 구현 인 std::function
은 값으로 가져갈 때 인수가 이동한다는 것을 알게되었습니다. 다음 코드는이 동작을 보여줍니다`std :: function`이 인수를 이동할 수 있습니까?
#include <functional>
#include <iostream>
struct CopyableMovable
{
CopyableMovable() { std::cout << "default" << '\n'; }
CopyableMovable(CopyableMovable const &) { std::cout << "copy" << '\n'; }
CopyableMovable(CopyableMovable &&) { std::cout << "move" << '\n'; }
};
void foo(CopyableMovable cm)
{ }
int main()
{
typedef std::function<void(CopyableMovable)> byValue;
byValue fooByValue = foo;
CopyableMovable cm;
fooByValue(cm);
}
// outputs: default copy move move
우리는 여기에서 볼 cm
의 사본이 수행되도록합니다 (byValue
의 매개 변수 값에 의해 촬영되어 있기 때문에 합리적인 것으로 보인다),하지만이 움직임이있다. function
이 cm
사본에서 작동하고 있기 때문에 인수가 이동한다는 사실은 중요하지 않은 구현 세부 사항으로 볼 수 있습니다. 그러나이 동작은 몇 가지 문제 when using function
together with bind
가 발생합니다
#include <functional>
#include <iostream>
struct MoveTracker
{
bool hasBeenMovedFrom;
MoveTracker()
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker const &)
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker && other)
: hasBeenMovedFrom(false)
{
if (other.hasBeenMovedFrom)
{
std::cout << "already moved!" << '\n';
}
else
{
other.hasBeenMovedFrom = true;
}
}
};
void foo(MoveTracker, MoveTracker) {}
int main()
{
using namespace std::placeholders;
std::function<void(MoveTracker)> func = std::bind(foo, _1, _1);
MoveTracker obj;
func(obj); // prints "already moved!"
}
표준에 의해 허용이 문제인가? std::function
은 (는) 해당 인수를 이동할 수 있습니까? 그렇다면 bind
에 의해 반환 된 래퍼를 by-value 매개 변수가있는 std::function
으로 변환 할 수 있습니다. 이는 여러 개의 자리 표시자를 처리 할 때 예기치 않은 동작을 유발할 수 있습니까?
문제는 'std :: function'보다 placeholder가 더 많은 것으로 보입니다. 즉, '동점'을 만들 때 원본 인수에서 예상되는 두 출력 모두로 이동한다는 사실. –
흥미롭게도 Visual C++ 11 컴파일러는 첫 번째 예제에서 "default copy move"를 인쇄하고 "already moved!" 두 번째. 이 추가 이동이 std :: function 및/또는 perfect forwarding의 내부 동작에서 오는 것인지 궁금합니다. –
@MatthieuM. 당신은 정교 할 수 있습니까? 자리 표시 자 구현에 익숙하지 않습니다. placeholder에서 문제가 발생했다면'std :: function' 대신'auto'를 사용하여 "bind-wrapper"유형을 추론 할 때 문제가 발생하지 않습니다. –