在解释与同事对对象的移动操作时,我基本上说移动操作不应该在容器中抛出异常,因为如果移动操作失败,则无法可靠地恢复原始对象.考虑到这一点,我想知道这是不是正确的,并且如果一个移动操作确实抛出,它可以将原始对象恢复到它的原始状态.
这样做的原因是,如果一个对象可以抛出,那么它将不会因为复制或将包含的对象从旧地址移动到新地址而抛出,而是在无法获取资源时抛出.所以所有的原始信息都应该存在.如果是这种情况,那么编译器是否应该无法反转它为重建原始对象所做的操作?
操作可能是一种方式,比如移动一个整数,但在这种情况下它可能只是终止应用程序,也许如果开发人员想要避免单向操作可以使用交换方法.
这只能在默认移动运算符上实现,就像有任何其他逻辑一样,编译器可能很难进行反向部分变换.
我是否过于简化了事情?有没有我遗漏的东西,如果没有非投掷移动构造函数/运算符,容器不会移动对象?
因此,我想练习的用法,std::forward并创建了Test具有2个构造函数的类。1个带T&,另一个带T&&作为过载。T&打印左值,并T&&打印右值,所以我知道正在使用哪个构造函数。我在堆栈上创建了2个类的实例,令我惊讶的是,这两个实例都使用了T&&重载。
#include <iostream>
#include <type_traits>
#include <utility>
template <class T> auto forward(T &&t) {
if constexpr (std::is_lvalue_reference<T>::value) {
return t;
}
return std::move(t);
}
template <class T> class Test {
public:
Test(T &) { std::cout << "lvalue" << std::endl; };
Test(T &&) { std::cout << "rvalue" << std::endl; };
};
int main() {
int x = 5;
Test<int> a(forward(3));
Test<int> b(forward(x));
return …Run Code Online (Sandbox Code Playgroud) 我有以下(设计)代码,其中我有一个打印机类,其中包含一个打印函数和一个处理字符串然后调用回调函数到print函数的工作类:
#include <functional>
#include <iostream>
using callback_fn = std::function<bool(std::string)>;
class printer
{
public:
bool print(std::string data)
{
std::cout << data << std::endl;
return true;
}
};
class worker
{
public:
callback_fn m_callback;
void set_callback(callback_fn callback)
{
m_callback = std::move(callback); // <-- 1. callback is a temp, so what does std::move do here?
}
void process_data(std::string data)
{
if (!m_callback(data)) { /* do error handling */ }
}
};
int main() {
printer p;
worker w;
w.set_callback( std::move([&](std::string s){ return p.print(s); …Run Code Online (Sandbox Code Playgroud) #include <functional>
#include <iostream>
#include <string>
#include <utility>
using namespace std;
template<typename Func, typename... Args>
void do_task(Func &func, Args &&...args)
{
auto f = bind(func, forward<Args>(args)...);
f();
}
int main()
{
string name = "hello";
auto test_func = [](string name, string &&arg1, string &&arg2) -> void {
cout << name << " " << arg1 << " " << arg2 << endl;
};
// do_task(test_func,"test_one", "hello", string("world")); // compile error
// do_task(test_func, "test_tww", std::move(name), "world"); // compile error
do_task(test_func, "test_three", …Run Code Online (Sandbox Code Playgroud) 以下是代码段:
int i=0;
int&&k=std::move(i);
Run Code Online (Sandbox Code Playgroud)
在c ++入门中,此举是
template <typename T>
typename remove_reference<T>::type &&move(T&& t)
{return static_cast<typename remove_reference<T>::type&&>(t);}
Run Code Online (Sandbox Code Playgroud)
据我所知,这个std::move模板会扣除一个像这样的函数
int&& move(int& t){return static_cast<int&&>(t);}
Run Code Online (Sandbox Code Playgroud)
作为比较和阐述我的问题,请考虑这样的示例:
int test(int k){k=66;return k;}
int k;
int a=test(k);
Run Code Online (Sandbox Code Playgroud)
上面的代码将编译为:
int temp;//the temporary object
temp=k;
int a=temp;
Run Code Online (Sandbox Code Playgroud)
同样,我认为第一个代码片段将被编译为:
int&& temp=0;
int&& k=temp;//oop!temp is an lvalue!
Run Code Online (Sandbox Code Playgroud)
这似乎是错误的,因为它temp是一个左值,我有什么不对吗?
我有一个函数返回一个 std::vector<std::byte>
我知道这std::byte不是字符类型也不是整数类型,并且只能通过类型转换将其转换为 char。到现在为止还挺好。
所以我想(在我知道向量只包含字符数据的情况下)将底层缓冲区的所有权从 thestd::vector<std::byte>转移到std::vector<char>using std::move,以避免复制整个底层缓冲区。
当我尝试这样做时,我收到此错误:
不存在从“std::vector<std::byte, std::allocatorsstd::byte>”到“std::vector<char,std::allocator>”的合适的用户定义转换
这完全可能使用 C++ 吗?我认为有真正的用例,人们会想要这样做
我最近开始使用c ++,我选择学习c ++ 11的功能.但是c ++代码的运行方式有时并不那么明显.
下面是我的代码.在那部分,decltype(std::move(sample)) sample2 = std::move(sample);我不知道为什么这一行不会调用移动构造函数.你能解释一下原因吗?
#include <iostream>
class AAA
{
public:
AAA() { std::cout << "default constructor" << std::endl; }
AAA(const AAA& cs) { std::cout << "copy constructor" << std::endl; }
AAA(AAA&& cs) { std::cout << "move constructor" << std::endl; }
~AAA() { std::cout << "destructor" << std::endl; }
};
int main(int argc, char* args[])
{
AAA sample;
// ((right here))
decltype(std::move(sample)) sample2 = std::move(sample);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它是在[ubuntu 16.04 …
在MSVC STL中,实现std::apply如下:
template <class _Callable, _Tuple_like _Tuple, size_t... _Indices>
constexpr decltype(auto) _Apply_impl(_Callable&& _Obj, _Tuple&& _Tpl, index_sequence<_Indices...>) noexcept(/* [...] */) {
return _STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...);
}
Run Code Online (Sandbox Code Playgroud)
在表达式 中_STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...,std::get被调用的次数与元组的长度相同。但是,每次调用 时std::get,都会有一个相应的调用std::forward.当转发右值时,std::forward相当于,意味着对该对象的std::move多次调用。这似乎可能是无效的。有人可以帮助解释我的担忧吗?std::move_Tpl
我尝试搜索各种资源,但找不到我正在寻找的答案。从定义开始也没有说服我。
我正在学习 CPP++14 移动语义。在编写一小段代码时,我观察到了一些奇怪的行为。我正在使用 r 值引用将唯一 ptr 的向量移动到函数。在调试时,我发现更改也应用于移动的对象。为什么即使物体被移动我也会观察这个hcnage?以下代码中的移动有什么作用?
void func(std::vector<std::unique_ptr<int>> && vect) {
vect.emplace_back(std::move(std::make_unique<int>(3)));
return ;
}
int main() {
std::vector<std::unique_ptr<int>> a;
func(std::move(a));
cout<<(*(a[0]))<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 考虑这个代码片段
#include <iostream>
int foo() {
int a;
return a;
}
int main() {
auto &&ret = std::move(foo());
std::cout << ret;
}
Run Code Online (Sandbox Code Playgroud)
使用ASAN编译g++ -fsanitize=address -fno-omit-frame-pointer -g -std=c++17 main.cpp -o main,运行./main显示错误
==57382==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00016b3cb480 at pc 0x000104a37e68 bp 0x00016b3cb450 sp 0x00016b3cb448
READ of size 4 at 0x00016b3cb480 thread T0
#0 0x104a37e64 in main main.cpp:8
#1 0x104a75084 in start+0x200 (dyld:arm64e+0x5084)
Run Code Online (Sandbox Code Playgroud)
但是如果我在 auto 之后删除引用,这段代码可以编译并运行,而不会出现 ASAN 给出的错误。我不明白的是,如果std::move返回对给定对象的引用,那么该对象(foo()在本例中是临时创建的)将在函数调用返回后被销毁std::move,因此无论它是绑定到右值引用还是分配给新值应该无效,因为该临时值在移动操作后已经被销毁,对吗?那么为什么 ASAN 在第二种情况下不会给出错误。
- - …