我正在使用std::moveon编写一些 C++ 代码shared_ptr,并得到了非常奇怪的输出。我简化了我的代码如下
int func(std::shared_ptr<int>&& a) {
return 0;
}
int main() {
std::shared_ptr<int> ptr = std::make_shared<int>(1);
for (int i = 0; i != 10; ++i) {
func(i == 9 ? std::move(ptr) : std::shared_ptr<int>(ptr));
}
if (ptr) {
std::cout << "ptr is not null: " << *ptr << "\n";
} else {
std::cout << "ptr is null\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了输出
ptr is null
Run Code Online (Sandbox Code Playgroud)
正如我所预期的,我的ptrwill 在最后一个循环中被移动(转换为std::shared_ptr<int>&&),并且由于func从不窃取 中的内存a,所以我的 …
c++ conditional-operator shared-ptr move-constructor move-semantics
我有一个类,它包含一个指向大块已分配内存和许多基本类型成员的指针.我正在考虑移动构造函数,并认为这是一个使用它的绝佳机会.显然,如果对于基元是一个好主意,指针应该移动但是idk.
以下是该课程的一个人为设想的例子:
class Foo {
private:
long m_bar = 1;
/* 20+ similar members */
};
Run Code Online (Sandbox Code Playgroud)
为了使它们可移动,必须动态分配它们.
class Foo {
public:
Foo(Foo && rhs) : m_bar(rhs.m_bar) { rhs.m_bar = nullptr; }
~Foo() { delete m_bar; }
private:
long *m_bar = new long{1};
};
Run Code Online (Sandbox Code Playgroud)
我的问题是,分配在堆上的开销是否会使移动语义引入的性能增加无效?
假设我有一个带有复制构造函数和移动构造函数的对象'foo',以及一个函数
foo f() {
foo bar;
/* do some work */
return bar;
}
Run Code Online (Sandbox Code Playgroud)
该标准似乎表明编译器将尝试执行:NRVO,通过r值ref返回,按值返回,失败; 以该顺序.
有没有办法强制编译器永远不会按值返回,因为我的复制构造函数非常昂贵?
c++ rvalue-reference move-constructor return-value-optimization c++11
我上课了
class A {
public:
A(){cout<<"C";}
~A(){cout<<"D";}
};
int main(){
unique_ptr<A> a(new A[5]); // - doesn't work
unique_ptr<A> a(new A[1]); // - doesn't work
unique_ptr<A> a(new A); // - works
}
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
我想这是关于移动构造函数(由于析构函数不能自动创建),但为什么我们需要一个移动构造函数呢?
有什么区别:
unique_ptr<A> a(new A[1]); // - doesn't work
unique_ptr<A> a(new A); // -works
Run Code Online (Sandbox Code Playgroud) 在下面的代码中,我创建了p const,因为在Foo的生命周期中它永远不会指向任何其他int.这不会编译,因为调用了unique_ptr的复制构造函数,这显然已被删除.除了使p非常数之外还有其他解决方案吗?谢谢.
#include <memory>
using namespace std;
class Foo
{
public:
//x is a large struct in reality
Foo(const int* const x) : p(x) {};
Foo(Foo&& foo) : p(std::move(foo.p)) {};
private:
const unique_ptr<int> p;
};
Run Code Online (Sandbox Code Playgroud) 我试图理解move-constructor的实现.我们都知道如果我们需要管理C++类中的资源,我们需要实现五阶规则(C++编程).
微软给我们举了一个例子:https://msdn.microsoft.com/en-us/library/dd293665.aspx
这是更好的一个,它使用copy-swap来避免代码重复: 动态分配一个对象数组
// C++11
A(A&& src) noexcept
: mSize(0)
, mArray(NULL)
{
// Can we write src.swap(*this);
// or (*this).swap(src);
(*this) = std::move(src); // Implements in terms of assignment
}
Run Code Online (Sandbox Code Playgroud)
在move-constructor中,直接:
// Can we write src.swap(*this);
// or (*this).swap(src);
Run Code Online (Sandbox Code Playgroud)
因为我觉得(*this) = std::move(src)有点复杂.因为如果我们(*this) = src无意中写,它会调用普通赋值运算符而不是move-assignment-operator.
除了这个问题,在微软的例子中,他们编写了这样的代码:在move-assignment-operator中,我们是否需要检查自我赋值?有可能发生吗?
// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other)
{
std::cout << "In operator=(MemoryBlock&&). length = "
<< other._length << "." << std::endl;
if (this != &other)
{ …Run Code Online (Sandbox Code Playgroud) 我正在尝试为使用类Id的对象A实现移动构造函数.类Id是自动生成的,为了将来的编码健全,我选择在我这样做时删除默认构造函数.
然而,当我尝试在A的移动构造函数中使用swap时,它抱怨Id的默认构造函数被删除.我认为交换不是构造任何新对象,而只是交换两个项目的地址.
我是否误解了它,它实际上是在创建第三个临时实例?
如果是这种情况,下面实现移动构造函数的最佳方法是什么?
我在下面列出了一个最小的例子:
class Id {
public:
Id() = delete;
Id(std::string id) : m_id(id) {}
private:
std::string m_id;
};
class A {
public:
A() = delete;
A(Id id) : m_id(id) {}
A(A&& other) {
std::swap(m_id, other.m_id);
}
private:
Id m_id;
};
Run Code Online (Sandbox Code Playgroud)
编译器返回以下错误:
In constructor 'A::A(A&&)':
21:18: error: use of deleted function 'Id::Id()'
8:5: note: declared here
In file included from /usr/include/c++/4.9/bits/stl_pair.h:59:0,
from /usr/include/c++/4.9/bits/stl_algobase.h:64,
from /usr/include/c++/4.9/bits/char_traits.h:39,
from /usr/include/c++/4.9/ios:40,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from 2:
/usr/include/c++/4.9/bits/move.h: …Run Code Online (Sandbox Code Playgroud) c++ rvalue default-constructor move-constructor move-semantics
我在使用C++理解移动构造函数时遇到了困难.我用默认构造函数,复制构造函数,移动构造函数和析构函数创建了一个简单的类.此外,我已经定义了一个具有两个重载的函数,一个接受对该类的引用,另一个接受对该类的右值引用.我的测试代码如下.
#include <iostream>
class c {
public:
c() {
std::cout << "default constructor" << std::endl;
}
c(const c& s) {
std::cout << "copy constructor" << std::endl;
}
c(c&& s) {
std::cout << "move constructor" << std::endl;
}
~c() {
std::cout << "destructor" << std::endl;
}
};
void f(c& s) {
std::cout << "passed by reference" << std::endl;
}
void f(c&& s) {
std::cout << "passed by rvalue reference" << std::endl;
}
int main() {
c s1; // line 1
std::cout …Run Code Online (Sandbox Code Playgroud) c++ rvalue-reference most-vexing-parse move-constructor move-semantics
我有一个std::vector类似的课程
struct Mystruct
{
Mystruct(const std::vector<int>& w): v(w)
{
std::cout << "Copy constructor :" << v.at(0) << "\n";
}
Mystruct(const std::vector<int>&& w): v(w)
{
std::cout << "Move Constructor :" << v.at(0) << "\n";
}
private:
std::vector<int> v;
};
Run Code Online (Sandbox Code Playgroud)
我创建像这样的对象
int main()
{
auto x = std::vector<int> {1,2,3};
Mystruct M1(x);
Mystruct M2(std::vector<int> {3,2,1});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
M1使用复制构造函数和M2使用"移动"构造函数构造,但是在gdb中运行时,两个分配都为v和w保留不同的地址,如果我在初始化列表中使用v(std :: move(w)),则会发生同样的情况.第二个构造函数.所以我猜两个人都在复制w的内容,这是正确的吗?如果是这种情况,我怎样才能移动w的内容而不是复制它们
我只是注意到我的一个std::vector<Foo>在调整大小时正在复制而不是移动它的元素 - 即使Foo有一个移动 ctor:
class Foo {
// ...
Foo(Foo&& other) : id_(other.id_), ptr_(other.ptr_), flag(other.flag)
{
other.flag = false;
};
// ...
int id_;
void* ptr_;
bool flag;
}
Run Code Online (Sandbox Code Playgroud)
然后我读到:
这提醒我,std::vector只有在声明了元素的移动构造函数时才会使用移动构造noexcept。当我添加时noexcept,会调用移动 ctor。
我的问题是:为什么,给定移动 ctor 的代码,编译器没有确定它是noexcept?我的意思是,它可以知道不能抛出异常的事实。此外,推断是否noexcept被标准禁止,或者不是由我的特定编译器完成的?
我在 GNU/Linux 上使用 GCC 5.4.0。
c++ ×10
move-constructor ×10
c++11 ×3
move ×2
unique-ptr ×2
const ×1
gcc ×1
noexcept ×1
rvalue ×1
shared-ptr ×1