如何修正代码使cookie_name_t仅使用移动构造与赋值(编译失败)
问题分析与代码修正
当你删除cookie_name的拷贝构造函数和拷贝赋值运算符后,包含它的std::tuple<cookie_name_t, cookie_value_t, cookie_options_t>会自动失去拷贝能力,原代码编译错误集中在insert_or_update函数的两处逻辑:
cookies_.emplace_back(cookie):函数参数里的cookie是右值引用,但在函数内部它是左值,调用emplace_back时会尝试拷贝tuple,而tuple中的cookie_name_t已禁用拷贝,导致编译失败。- 需要确保所有涉及tuple的操作都优先使用移动语义,避免隐式拷贝触发错误。
具体修正步骤
- 修复
insert_or_update中的emplace_back调用
将传递cookie改为std::move(cookie),强制触发tuple的移动构造:
if (value == cookies_.end()) cookies_.emplace_back(std::move(cookie));
- 优化
cookie_name的operator()返回值(推荐)
原operator()返回value_type的拷贝,改成返回const引用可避免不必要的拷贝,同时不影响功能:
const value_type& operator()() const noexcept { return value_; }
- 可选:添加右值引用版本的
cookie成员函数
如果需要支持直接传入cookie_name_t的右值,可新增重载函数,利用移动语义提升性能:
void cookie(cookie_name_t&& cookie, cookie_value_t const &value) { insert_or_update(std::make_tuple(std::move(cookie), value(), std::string{})); }
完整修正代码
class cookie_name final { public: using value_type = std::string; cookie_name() = delete; cookie_name(value_type const &value) noexcept(std::is_nothrow_copy_constructible_v<value_type>) : value_{value} {}; cookie_name(value_type &&value) noexcept(std::is_nothrow_move_constructible_v<value_type>) : value_{std::move(value)} {}; // 禁用拷贝构造和拷贝赋值 cookie_name(cookie_name const &) = delete; cookie_name &operator=(cookie_name const &) = delete; // 默认移动构造和移动赋值 cookie_name(cookie_name &&) noexcept(std::is_nothrow_move_constructible_v<value_type>) = default; cookie_name &operator=(cookie_name &&) noexcept(std::is_nothrow_move_assignable_v<value_type>) = default; // 返回const引用避免不必要拷贝 const value_type& operator()() const noexcept { return value_; } bool operator==(cookie_name const &rhs) const noexcept { return this->value_ == rhs.value_; } bool operator!=(cookie_name const &rhs) const noexcept { return !(this->value_ == rhs.value_); } private: value_type value_; }; using cookie_name_t = cookie_name; using cookie_value_t = cookie_value; // 假设cookie_value类已正确定义 using cookie_options_t = std::string; // 假设原代码中cookie_options_t为std::string class cookies final { public: using cookie_t = std::tuple<cookie_name_t, cookie_value_t, cookie_options_t>; private: using raw_cookie_t = std::vector<cookie_t>; public: cookies() = default; void cookie(cookie_name_t const &cookie, cookie_value_t const &value) { insert_or_update(std::make_tuple(cookie(), value(), std::string{})); } // 可选:支持右值引用的重载 void cookie(cookie_name_t&& cookie, cookie_value_t const &value) { insert_or_update(std::make_tuple(std::move(cookie), value(), std::string{})); } auto write_cookies() const; // 假设该函数已正确实现 private: void insert_or_update(cookie_t &&cookie); private: raw_cookie_t cookies_; }; void cookies::insert_or_update(cookie_t &&cookie) { auto value{std::find_if(cookies_.begin(), cookies_.end(), [&cookie](auto &iter) { return std::get<0>(iter)() == std::get<0>(cookie)(); })}; if (value == cookies_.end()) cookies_.emplace_back(std::move(cookie)); // 触发移动构造 else *value = std::move(cookie); // 触发移动赋值 }
关键说明
- 禁用拷贝后,所有涉及
cookie_name_t的容器操作必须通过std::move转换为右值引用,触发移动构造/赋值。 std::tuple的移动操作会自动调用成员的移动逻辑,只要cookie_name_t、cookie_value_t、cookie_options_t支持移动,tuple的移动就能正常工作。- 调整
operator()返回const引用可减少字符串拷贝开销,提升代码性能。
内容的提问来源于stack exchange,提问作者Tippa Toppa
相关产品推荐
相关产品推荐

