发生了什么:在std::shared_ptr上使用C++ std::move会增加use_count吗?

32

我一直认为在 std::shared_ptr 上使用 std::move() 会窃取指针并将原始指针设置为 nullptr,因此不会增加引用计数。但在我的环境中似乎并非如此。

设置

MacOS,g++ -version => "Apple LLVM version 10.0.1 (clang-1001.0.46.3)"

代码

#include <cstdio>                                                                                                                                                                                  
#include <memory>
class Thing { public: Thing(int N) : value(N) {} int value; };

void print(const char* name, std::shared_ptr<Thing>& sp)
{ printf("%s: { use_count=%i; }\n", name, (int)sp.use_count()); }

int main(int argc, char** argv) {
    std::shared_ptr<Thing>  x(new Thing(4711));
    print("BEFORE x", x);
    std::shared_ptr<Thing>  y = std::move(x);
    y->value = 4712;
    print(" AFTER x", x);
    print(" AFTER y", y);
    return 0;
}

输出:

编译 (g++ tmp.cpp -o test),运行 (./test),得到

BEFORE x: { use_count=1; }
 AFTER x: { use_count=2; }
 AFTER y: { use_count=2; }

因此,在使用 std::move() 时引用计数会增加。

问题:

这是怎么回事?


2
修复 UB 后,无法重现 - Marek R
就我所知,我使用的版本几乎相同,但库代码与报告不匹配,前提是_LIBCPP_HAS_NO_RVALUE_REFERENCES未定义。 - Lightness Races in Orbit
1个回答

43

这里发生了什么?

在 MacOS 上,似乎必须使用 -std=c++11(或更高版本)¹ 明确启用移动语义。否则,示例代码虽然可以编译通过(即相关库实现中的std::shared_ptr可用),但由于未启用所需的语言功能,它不能正常工作,实际上会进行复制而不是移动构造。如果 AppleClang 软件包在未启用所需语言功能的情况下甚至不允许实例化std::shared_ptr将会更好。

¹)感谢 @t.niese 测试给定的编译器/平台。


1
@lubgr 我可以确认,在给定的Mac编译器上编译并运行您的代码将导致use_count=2;,但在例如wandbox上将导致use_count=1; - t.niese
2
只有在使用 g++ tmp.cpp -o testg++ -std=c++11 tmp.cpp -o test 或者 g++ -std=c++17 tmp.cpp -o test 进行编译时,才会显示 use_count=1; - t.niese
2
听起来使用的标准库允许使用C++11特性(std::shared_ptr),而不启用语言支持(移动语义),这会导致实际复制。 - lubgr
默认情况下,@lubgr编译时使用的是c++11之前的版本。因此,std::move什么也不做,只会创建一个副本。 - t.niese
@lubr:我编辑了我的问题,使得print函数只打印引用计数,因为那是核心问题。你可能想要删除你问题的前半部分。 - Frank-Rene Schäfer
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接