You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义mymove函数为何无法像std::move一样触发移动构造函数?

为什么自定义mymove触发复制构造而std::move触发移动构造?

我为探究std::move的工作原理,模仿(甚至复制标准代码)实现了自定义mymove函数,但意外发现其无法像std::move一样工作——自定义函数最终调用的是复制构造函数(copy ctor)而非移动构造函数(move ctor)。

我通过#ifdef区分实现了两种版本:一种是近似写法,另一种是完全复制std::move的实现,但两者均触发复制构造,而std::move则正常触发移动构造。

测试代码

#include <iostream>

#define My_version

template <class _Ty>
struct remove_reference {
    using type = _Ty;
    using _Const_thru_ref_type = const _Ty;
};
template <class _Ty>
using remove_reference_t = typename remove_reference<_Ty>::type;

#ifdef My_version
template<typename T> // in namespace std
typename remove_reference<T>::type&&
mymove(T&& param)
{
    std::cout << "My_version\n";
    using ReturnType = typename remove_reference<T>::type&&; 
    return static_cast<ReturnType>(param);
}
#else
template <class _Ty>
constexpr remove_reference_t<_Ty>&& mymove(_Ty&& _Arg) noexcept { // forward _Arg as movable
    return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}
#endif // My_version

class simple
{
public:
    simple(int kk) :k(kk) {}
    
    simple(simple&& rhs) noexcept
    {
        std::cout << "move is called \n";
        k = rhs.k;
        rhs.k = -1; //moved
    }

    simple(const simple& rhs)noexcept
    {
        std::cout << "copy is called \n";
        k = rhs.k*10;
    }
    int k;
};

int main()
{
   
        {
            std::cout << "===============================\nmymove\n===============================\n";
            simple a(42);
            simple b = mymove(a);
            std::cout << " after move\nmovedObj.k " << b.k << " originalObj.k " << a.k << "\n";
        }
        {
            std::cout << "\n\n===============================\nstd::move\n===============================\n";
            simple a(42);
            simple b = std::move(a);
            std::cout << "after move\nmovedObj.k " << b.k << " originalObj.k " << a.k << "\n";
        }
   return 0;
}

运行输出

===============================
mymove
===============================
copy is called
 after move
movedObj.k 420 originalObj.k 42


===============================
std::move
===============================
move is called
after move
movedObj.k 42 originalObj.k -1

问题原因

核心问题出在你自定义的remove_reference结构体上——它缺少针对左值引用和右值引用的特化版本。

标准库中的std::remove_reference包含三个特化:

// 主模板
template<class T> struct remove_reference { using type = T; };
// 左值引用特化
template<class T> struct remove_reference<T&> { using type = T; };
// 右值引用特化
template<class T> struct remove_reference<T&&> { using type = T; };

当你调用mymove(a)时,a是左值,模板参数T会被推导为simple&(引用折叠规则:T&&传入左值时,T被推导为左值引用,最终参数类型变为simple& && → simple&)。此时你的自定义remove_reference<simple&>::type还是simple&,所以mymove的返回类型是simple& &&,再次触发引用折叠,最终返回simple&(左值引用)。

左值引用会匹配simple的复制构造函数(const simple&可以绑定左值),因此触发了复制构造而非移动构造。

而std::move依赖的标准库std::remove_reference是完整实现的,能正确将simple&转换为simple,因此返回simple&&(右值引用),匹配移动构造函数。

修复方案

给自定义的remove_reference补充特化版本:

template <class _Ty>
struct remove_reference {
    using type = _Ty;
    using _Const_thru_ref_type = const _Ty;
};
// 左值引用特化
template <class _Ty>
struct remove_reference<_Ty&> {
    using type = _Ty;
    using _Const_thru_ref_type = const _Ty&;
};
// 右值引用特化
template <class _Ty>
struct remove_reference<_Ty&&> {
    using type = _Ty;
    using _Const_thru_ref_type = const _Ty&&;
};

补充后,remove_reference<simple&>::type会被正确推导为simple,mymove返回simple&&,就能触发移动构造函数了。

内容的提问来源于stack exchange,提问作者V.Visana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 18:54:56