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

C++中std::future未返回值引用的问题排查

C++ std::future返回string地址不一致的原因解析

我刚开始学习C++多线程,在学习过程中发现打印std::future返回的string内存地址时,地址不一致。

原始代码

#include<iostream>
#include <thread>
#include <future>
#include <string>

void thFunc(std::promise<std::string> && prms) {
  std::string str("Hello from future ^^");
  std::cout << "Location=" << (void*)str.data() << "\n";
  prms.set_value(str);
}

int main() {
  std::promise<std::string> prms;
  std::future<std::string> ftr = prms.get_future();
  std::thread th(&thFunc, std::move(prms));
  std::printf("Hello from main!!\n");

  std::string futStr = ftr.get();
  std::cout << futStr << "\t Location= " << (void*)futStr.data() << "\n";
  th.join();
  return 0;
}

编译命令

clang++ -g -Wall -std=c++11 -stdlib=libc++ -o future_ex future_ex.cpp

运行输出

Hello from main!!
Location=0x30cdbff01
Hello from future ^^     Location= 0x30cd3dfa1

我查阅了std::future::get的文档,了解到它使用std::move,理论上不会有拷贝,但地址仍不一致,希望得到该行为的解释。


编辑后的代码(改用shared_ptr)

void thFunc(std::promise<std::shared_ptr<std::string>> & prms) {
  std::string str("Hello from future ^^");
  std::shared_ptr<std::string> shared = std::make_shared<std::string>(str);
  std::cout << "Address in thread=" << shared.get() << " String= " << *shared.get() << "\n";
  prms.set_value(shared);
}

int main() {
  std::promise<std::shared_ptr<std::string>> prms;
  std::future<std::shared_ptr<std::string>> ftr = prms.get_future();
  std::thread th(&thFunc, std::ref(prms));
  std::printf("Hello from main!!\n");

  std::shared_ptr<std::string> futSharedPtr = ftr.get();
  std::cout << "Address in main= " << futSharedPtr.get() << " Value= " << *futSharedPtr.get() << "\n";
  std::cout << "COUNT:: " << futSharedPtr.use_count() << "\n";
  th.join();
  return 0;
}

编辑后运行输出

Hello from main!!
Address in thread=0x60000298c018 String= Hello from future ^^
Address in main= 0x60000298c018 Value= Hello from future ^^
COUNT:: 1

原因解析

string地址不一致的核心原因

  1. promise.set_value触发的第一次拷贝
    线程中的prms.set_value(str)传递的是左值str,会调用set_value的左值重载,直接把str的内容拷贝到promise的共享状态中。这一步已经让字符串的存储地址从线程栈上的str变成了共享状态内部的新对象,地址自然改变。

  2. future.get的移动无法保留原始地址
    调用ftr.get()时,确实会将共享状态中的string移动到主线程的futStr中,但这无法让地址和线程里的str一致:

    • 你的字符串长度较短,触发了libc++的小字符串优化(SSO)——短字符串直接存在string对象的内部缓冲区(栈内存),而非堆上。移动这类string时,本质是复制对象内部的字符数组,而非转移堆指针,所以地址再次变化。
    • 即使是堆上的string,共享状态的内存位置和主线程futStr的栈帧完全不同,移动操作只是把共享状态中string的堆指针转移给futStr,但这个堆指针本身就和线程里str的堆指针不一样(因为第一步已经拷贝到共享状态了)。

shared_ptr能保持地址一致的原因

shared_ptr存储的是指向堆上string对象的指针:

  • 无论是prms.set_value(shared)还是ftr.get(),传递的都是shared_ptr的拷贝(或移动),但所有shared_ptr实例都指向同一个堆上的string对象。
  • 线程中的shared在函数结束后被销毁,所以主线程的futSharedPtr的use_count()为1,但堆上string的地址始终未变,因此前后打印的地址完全一致。

内容的提问来源于stack exchange,提问作者cicada_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:52:13