我刚才已经问了一个类似的问题,但我仍然不清楚一些细节.
在什么情况下postblit构造函数调用?
移动对象的语义是什么?它会被后照亮和/或破坏吗?
如果按值返回局部变量会发生什么?它会被隐含地移动吗?
如何将表达式转换为右值?例如,通用交换如何?
请考虑以下代码:
#include <vector>
class A
{
public:
A(A&&); // somewhat expensive
static std::vector<A> make_As()
{
std::vector<A> result;
result.push_back(A(3));
result.push_back(A(4));
return result;
}
private:
A(int); // private constructor
};
Run Code Online (Sandbox Code Playgroud)
因为A移动构造函数有些昂贵(无论出于何种原因),我想避免调用它并使用emplace_back():
#include <vector>
class A
{
public:
A(A&&); // somewhat expensive
static std::vector<A> make_As()
{
std::vector<A> result;
result.emplace_back(3);
result.emplace_back(4);
return result;
}
private:
A(int); // private constructor
};
Run Code Online (Sandbox Code Playgroud)
不幸的是,emplace_back()实际的构造函数调用是由标准库中的某些东西完成的,它没有足够的特权来调用A私有构造函数.
我意识到可能没有什么可以做的,但是我觉得既然调用emplace_back()发生在一个成员中A,他们应该能够调用私有构造函数.
这有什么变通方法吗?
我唯一能想到的是添加一个friend-declaration A,但是需要成为A朋友的精确类(即实际尝试调用构造函数的类)是特定于实现的(例如,for海湾合作委员会(GCC __gnu_cxx::new_allocator<A>)). …
在阅读了@Mehrdad 最近的问题之后,哪些类应该是不可移动的,因此是不可复制的,我开始想知道是否存在可以复制但不能移动的类的用例.从技术上讲,这是可能的:
struct S
{
S() { }
S(S const& s) { }
S(S&&) = delete;
};
S foo()
{
S s1;
S s2(s1); // OK (copyable)
return s1; // ERROR! (non-movable)
}
Run Code Online (Sandbox Code Playgroud)
虽然S有一个复制构造函数,但它显然不会对CopyConstructible概念进行建模,因为这反过来又是MoveConstructible概念的改进,需要存在(未删除的)移动构造函数(参见§17.6.3.1/2,表21) .
是否有类似S上述类型的用例,可复制但不可 CopyConstructible 移动?如果没有,为什么不禁止在同一个类中声明复制构造函数和已删除的移动构造函数?
以下代码无法使用Visual Studio 2013进行编译:
#include <vector>
struct X {
X() = default;
X(const X&) = delete;
X& operator=(const X&) = delete;
X(X&&) = delete;
X& operator=(X&&) = delete;
~X() = default;
};
void foo()
{
std::vector<X> v;
std::vector<X> w;
w = std::move(v);
}
Run Code Online (Sandbox Code Playgroud)
错误消息说
error C2280: 'X::X(X &&)' : attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)
这对我来说毫无意义.你不应该需要移动构造函数X来移动vector<X>.这是编译器错误,还是我错过了什么?
这是完整的错误消息:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xmemory0(600): error C2280: 'X::X(X &&)' : attempting to reference a deleted function
Test.cpp(9) : see …Run Code Online (Sandbox Code Playgroud) 我正在编写一个链表来包围Rust的生命周期,所有权和引用.我有以下代码:
pub struct LinkedList {
head: Option<Box<LinkedListNode>>,
}
pub struct LinkedListNode {
next: Option<Box<LinkedListNode>>,
}
impl LinkedList {
pub fn new() -> LinkedList {
LinkedList { head: None }
}
pub fn prepend_value(&mut self) {
let mut new_node = LinkedListNode { next: None };
match self.head {
Some(ref head) => new_node.next = Some(*head),
None => new_node.next = None,
};
self.head = Some(Box::new(new_node));
}
}
fn main() {}
Run Code Online (Sandbox Code Playgroud)
但是我收到以下编译错误:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:18:52
|
18 | …Run Code Online (Sandbox Code Playgroud) 这里记录了Rust的移动语义的一个很好的例子:在Rust By Example网站上的Rust Move Semantics.
我对两个案例都有基本的了解.第一个是原语如何具有新别名,原始仍然可以使用,因为最终结果是看到i32利用Copy特征的副本.这对我来说很有意义.
此外,由于许多好的理由,第二个示例在具有多个引用i32堆上的别名方面是有意义的.Rust强制执行所有权规则,因此现在无法使用原始别名创建新绑定.这有助于防止数据争用,双重释放等.
但似乎还有第三个案例没有被谈到.Rust如何实现不实现Copy特征的堆栈分配结构的移动? 使用以下代码对此进行说明:
#[derive(Debug)]
struct Employee{
age: i32,
}
fn do_something(m: Employee){
println!("{:?}", m);
}
fn main() {
let x = Employee {
age: 25,
};
do_something(x);
//compiler error below because x has moved
do_something(x);
}
Run Code Online (Sandbox Code Playgroud)
我知道:在上面的例子中,Rust会Employee在堆栈上分配.上述结构不实现Copy特征,因此在分配给新别名时不会被复制.这对我来说非常混乱,因为如果Employee结构被分配在堆栈上并且也没有实现Copy特性在哪里/如何移动?它是否在物理上移动到do_something()堆栈框架?
在解释这个难题时,我们对任何帮助表示赞赏.
std::any根据本Wiki中提供的规范实现C++ 17时,我偶然发现了一些对我来说荒谬的事情:
在自由函数的定义中std::any_cast,用于从std::any实例中检索值,提供了r值引用的重载(它是第三个):
template< class ValueType >
ValueType any_cast(any&& operand); // (3)
Run Code Online (Sandbox Code Playgroud)
现在,在概要下面列出的要求适用于重载2和3(这也意味着包括r值重载):
2-3)返回*any_cast<std::remove_reference_t<ValueType>>(&operand)
该定义似乎实际上不允许移动数据!
函数调用只是重定向到基于指针的重载; 有关临时性质的信息operand 丢失了!
是不是我不能离开任何一个实例?这只是wiki中的一个错误吗?我错了吗?
我正在看一些代码,我看到以下功能:
template <typename... Args>
static return_t make_return(Args &&... args)
{
// using std::forward<Args> will preserve lvalue args as such, but the point of this function
// is to make a return, where the 99.9+% case is moving a local (lvalue) into the return pack.
// Thus it forces a move, which will move `T&` args (but _not_ `const T&` args) into the
// return pack so that users don't need to type out a bunch of std::moves themselves/
// If …Run Code Online (Sandbox Code Playgroud) 我对本地范围内的任何对象的默认行为是 make it const。例如:
auto const cake = bake_cake(arguments);
Run Code Online (Sandbox Code Playgroud)
我尽量减少非功能性代码,因为这会增加可读性(并为编译器提供一些优化机会)。所以在类型系统中也反映这一点是合乎逻辑的。
然而,使用移动语义,这会产生问题:如果我cake很难或不可能复制并且我想在完成后将其传递出去怎么办?例如:
if (tastes_fine(cake)) {
return serve_dish(cake);
}
Run Code Online (Sandbox Code Playgroud)
据我了解复制cake省略规则,不能保证副本会被删除(但我不确定这一点)。
所以,我不得不搬出cake去:
return serve_dish(std::move(cake)); // this will not work as intended
Run Code Online (Sandbox Code Playgroud)
但这std::move不会有任何用处,因为它(正确地)不会转换Cake const&为Cake&&. 即使对象的生命周期已接近尾声。我们不能从我们承诺不会改变的东西中窃取资源。但这会削弱常量正确性。
那么,我怎样才能拥有我的蛋糕并吃掉它呢?
(即我怎样才能拥有常量正确性并从移动语义中受益。)
当移动-构造std::function从一个对象的λ,其中该拉姆达具有由值捕获,看来该物体的移动,构造函数,是值捕获被调用两次。考虑
#include <功能>
#include <iostream>
结构体
{
整数值 = 1;
Foo() = 默认值;
Foo(const Foo &) {}
富(富&&)
{
std::cout << "移动构造函数" << std::endl;
}
};
int main()
{
福福;
自动 lambda = [=]() { 返回 foo.value; };
std::cout << "---------" << std::endl;
std::function<int()> func(std::move(lambda));
std::cout << "---------" << std::endl;
返回0;
}
输出是
---------
move ctor
move ctor
---------
Run Code Online (Sandbox Code Playgroud)
我在 Mac OS X Catalina 上工作,我的编译器是
g++-9 (Homebrew GCC 9.3.0) 9.3.0
Run Code Online (Sandbox Code Playgroud)
我用g++ -std=c++17. …
move-semantics ×10
c++ ×7
c++11 ×4
c++17 ×3
rust ×2
d ×1
lambda ×1
reference ×1
return-value ×1
std ×1
std-function ×1
stdtuple ×1
templates ×1