今天我发现这段代码并没有像我期望的那样工作。根据我的知识,对于 L 值,应该调用复制构造函数,而对于 R 值,应该选择移动构造函数。否则它的目的是什么,std::move实际上什么也不做,只是转换为 R 值。我原以为return obj会调用复制构造函数,但它调用了 move。我知道复制在这里毫无用处,但这就是规则。如果我的复制构造函数有副作用,这就是我的情况,该怎么办(我知道它不应该,但从技术上讲它可以 - 例如这里:std::cout 调用)。标准中有什么允许这种行为的吗?另外我怎样才能强制复制?
#include <iostream>
class X
{
public:
X() = default;
X(const X& r): i(r.i)
{
std::cout << "copy ctor" << std::endl;
}
X(const X&& r): i(r.i)
{
std::cout << "move ctor" << std::endl;
}
int i = 0;
};
X foo()
{
X obj;
obj.i = 10;
return obj;
}
int main()
{
X x = foo();
}
Run Code Online (Sandbox Code Playgroud)
移动演员
移动演员
我有以下模板类,其中成员是const ref类型。对象的复制被禁用,并且只需要移动对象和移动赋值运算符。
Q1:如何const ref type正确实现移动赋值运算符(我所做的是否正确)?
Q2:为什么会这样
MyClass<int> obj2(std::move(obj)); // will work with move ctor
MyClass<int> obj3 = std::move(obj2); // also move ctor called: Why?
Run Code Online (Sandbox Code Playgroud)
发生了?
Q3:在main()移动实例中是否可以调用using print()。是UB吗?
我正在使用Visual Studio 2015 (v140)。这是我的代码:
#include <utility>
#include <iostream>
template<typename Type>
class MyClass
{
const Type& m_ref; // const ref type
public:
explicit MyClass(const Type& arg): m_ref(std::move(arg)){}
// coping is not allowed
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
// …Run Code Online (Sandbox Code Playgroud) 我想在我的应用程序中使用移动语义,而不是复制数据。\n以下是代码:
\n\nusing namespace std;\n\nstruct TestData\n{\n TestData(const TestData&) = delete;\n TestData& operator=(const TestData&) = delete;\n TestData(TestData &&other) = default;\n TestData& operator=(TestData &&other) = default;\n\n TestData() { std::cout << "TestData()" << std::endl; }\n ~TestData() noexcept {\n if(ptr != null) delete []ptr;\n std::cout << "~TestData(), ptr = " << (ptr == nullptr ? "nullptr" : "not null") << std::endl; \n }\n int x;\n char *ptr = nullptr;\n};\n\nvoid add(std::vector<TestData> &vector)\n{\n TestData d;\n d.x = 1;\n d.ptr = new char[12];\n memcpy(d.ptr, "Test string", 11);\n …Run Code Online (Sandbox Code Playgroud) 有人可以向我解释一件事吗?从一方面来看,它的move constructor设计目的是通过消除不必要的复制对象来优化内存和处理器的使用,但从另一面来看,几乎所有地方move constructor都会使用编译器使用复制省略move ctor,禁用?的使用。这不是不合理吗?
我有一堆带有 inputx和y. 我允许输入类型通过引用传递(如果它已经存在)和通过临时输入(使用&&)(如果不存在并且需要创建一个临时对象)。
基本上,我定义和重载函数如下
double foo(const std:::vector<int> & x, const std:::vector<int> & y){
// Do something
}
double foo(const std:::vector<int> & x,std:::vector<int>&& y){
// Do something
}
double foo(std:::vector<int>&& x,const std:::vector<int> & y){
// Do something
}
double foo(std:::vector<int>&& x,std:::vector<int>&& y){
// Do something
}
Run Code Online (Sandbox Code Playgroud)
//Do something 完全相同,但唯一的区别是输入类型。有没有一种方法可以在没有太多冗余的情况下简化代码?我不想有foo(std:::vector<int> x,std:::vector<int> y)内存问题。
编辑:有时我还必须稍微修改输入。可能有三种类型的不同子集std::vector<int> &,std::vector<int> &&,const std::vector<int> &的x和y。
正如@AVH(谢谢!)指出的那样,如果它只是 from std::vector<int> &&,const std::vector<int> &,const std::vector<int> &应该足以完成这项工作。
结合@Ken Wayne …
如果我们写如下函数:
auto foo() {
Foo foo { /* ... */ };
do_stuff(foo);
return foo;
}
Run Code Online (Sandbox Code Playgroud)
然后NRVO应该启动,这样foo就不会在返回时被复制。
现在假设我想返回两个不同的值:
auto foo() {
Foo foo { /* ... */ };
Bar bar { /* ... */ };
do_stuff(foo, bar);
return std::make_tuple(foo, bar);
}
Run Code Online (Sandbox Code Playgroud)
这种幼稚的实现可能会触发构建每个Foo和Bar( GodBolt)的两个副本。
我应该如何最好地修改我的代码以避免这种复制,而不会弄乱我的返回类型?
在 C++ 标准vector.capacity部分,它为 定义了两个重载resize()。(另见https://en.cppreference.com/w/cpp/container/vector/resize)
此重载要求类型 T 是MoveInsertableand DefaultInsertable:
constexpr void resize(size_type sz);
Run Code Online (Sandbox Code Playgroud)
另一个重载要求类型 T 是CopyInsertable:
constexpr void resize(size_type sz, const T& c);
Run Code Online (Sandbox Code Playgroud)
标准中提到的部分的第 16 条规定了第一次重载:
如果非 Cpp17CopyInsertable T的移动构造函数引发异常,则不会产生任何影响。
但是对于第二次重载,它指出:
如果抛出异常,则没有任何影响。
第二个重载中没有提到移动构造函数的抛出。为什么?
我有关于发电机的这个问题:
use tokio::runtime::Runtime;
use tokio::task::JoinHandle;
use std::sync::Arc;
pub fn run(f: Box<dyn Fn() -> Result<(), ()> + Send>) {
f();
}
fn main() {
let x = Arc::new(0);
run(Box::new(move ||{
let rt = Runtime::new().unwrap();
let _t = rt.block_on(async move {
let y = x;
});
Ok(())
}));
}
Run Code Online (Sandbox Code Playgroud)
错误:
error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
--> src/main.rs:13:41
|
10 | let x = Arc::new(0);
| - captured outer variable
...
13 | let …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个函数,该函数使用迭代器&[Vec<u64>]为i64每行中最大的一个返回元组“坐标”向量。我有它在具体类型上工作,但我希望它是通用的,T并且限制为可迭代类型。到目前为止我的代码:
fn find_largest_per_row<T>(input: &[T]) -> Vec<(usize, usize)>
where
T: IntoIterator<Item = u64>,
{
input
.iter()
.enumerate()
.map(|(r, v)| {
v.into_iter()
.enumerate()
.max_by_key(|&(_, v)| v)
.map(|(c, _)| (r, c))
.unwrap()
})
.collect::<Vec<_>>()
}
Run Code Online (Sandbox Code Playgroud)
我越来越:
fn find_largest_per_row<T>(input: &[T]) -> Vec<(usize, usize)>
where
T: IntoIterator<Item = u64>,
{
input
.iter()
.enumerate()
.map(|(r, v)| {
v.into_iter()
.enumerate()
.max_by_key(|&(_, v)| v)
.map(|(c, _)| (r, c))
.unwrap()
})
.collect::<Vec<_>>()
}
Run Code Online (Sandbox Code Playgroud)
我该如何解决?我意识到T是一个参考,所以我尝试了.cloned(),但这没有用。
另外,对于IntoIterator<Item=u64>,我需要指定u64还是可以提供更通用的东西?
我想弄清楚为什么这段代码不能编译?我已经创建了用户定义的析构函数,因此不应创建移动构造函数和移动赋值运算符。那么为什么复杂化失败,说我的班级不符合要求?
#include <iostream>
#include <concepts>
#include <type_traits>
template<class T> requires (!std::movable<T>)
struct Singleton
{
};
struct Widget
{
~Widget() = default;
};
int main()
{
auto x = Singleton<Widget>{};
}
Run Code Online (Sandbox Code Playgroud)
编辑。这个版本也是如此。
#include <iostream>
#include <concepts>
#include <type_traits>
extern void fun();
template<class T> requires (!std::movable<T>)
struct Singleton
{
};
struct Widget
{
~Widget()
{
fun();
}
};
int main()
{
auto x = Singleton<Widget>{};
}
Run Code Online (Sandbox Code Playgroud)
错误信息
:23:28: 注意: 不满足约束: 替换“模板需要 !(movable) > struct Singleton [with T = Widget]”: :23:28: 从这里需要 :8:8: …
move-semantics ×10
c++ ×7
c++11 ×4
copy-elision ×2
rust ×2
constructor ×1
gcc ×1
generics ×1
nrvo ×1
stdmove ×1
stdvector ×1
traits ×1