相关疑难解决方法(0)

什么是复制和交换习语?

这个成语是什么,什么时候应该使用?它解决了哪些问题?当使用C++ 11时,成语是否会改变?

虽然在许多地方已经提到过,但我们没有任何单一的"它是什么"问题和答案,所以在这里.以下是前面提到的地方的部分列表:

c++ c++-faq copy-constructor assignment-operator copy-and-swap

1907
推荐指数
5
解决办法
34万
查看次数

是x = std :: move(x)未定义?

我们x是某种类型的先前已初始化的变量.是以下行:

x = std::move(x)
Run Code Online (Sandbox Code Playgroud)

未定义?这个标准在哪里?它对它有什么看法?

c++ language-lawyer c++11 c++14

61
推荐指数
3
解决办法
2892
查看次数

标准库如何实现std :: swap?

如何在STL中实现交换功能?它是这么简单:

template<typename T> void swap(T& t1, T& t2) {
    T tmp(t1);
    t1=t2;
    t2=tmp;
}
Run Code Online (Sandbox Code Playgroud)

在其他帖子中,他们谈论为您自己的班级专门化这个功能.我为什么要这样做?为什么我不能使用这个std::swap功能?

c++ templates swap

58
推荐指数
2
解决办法
2万
查看次数

标准库对自动分配的保证是什么?

C++ 11标准对标准库相关的自移动赋值有何看法?更具体的是,什么(如果有的话)保证什么selfAssign呢?

template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
  v = std::move(v);
  return v;
}
Run Code Online (Sandbox Code Playgroud)

c++ stl move-semantics c++11

41
推荐指数
2
解决办法
3488
查看次数

std :: swap(x,x)是否保证x不变?

这个问题是基于Scott Meyers最近发表的博客文章.

看起来"显而易见" std::swap(x, x)应该x在C++ 98和C++ 11中保持不变,但我无法在任何标准中找到任何保证.C++ 98 std::swap在复制构造和复制赋值方面进行了定义,而C++ 11则根据移动构造和移动赋值来定义它,这似乎是相关的,因为在C++ 11(和C++ 14)中,17.6 .4.9表示移动分配不需要自我分配安全:

如果函数参数绑定到右值引用参数,则实现可以假定此参数是对此参数的唯一引用.... [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数move(x)调用函数),程序实际上要求该函数将该左值视为暂时的.实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查. - 尾注]

引起这种措辞的缺陷报告使结果清晰:

这澄清了移动赋值运算符不需要执行复制赋值运算符中常见(并且需要)的传统if(this!=&rhs)测试.

但是在C++ 11和C++ 14中,std::swap预计会使用这个实现,

template<typename T>
void swap(T& lhs, T& rhs)
{
  auto temp(std::move(lhs));
  lhs = std::move(rhs);
  rhs = std::move(temp); 
}
Run Code Online (Sandbox Code Playgroud)

并且第一个赋值是对self进行赋值,其中参数是rvalue.如果移动赋值运算符T遵循标准库的策略并且不担心赋值给自己,那么这似乎可以判断未定义的行为,这也意味着它std::swap(x, x)也会具有UB.

即使是孤立的,这也是令人担忧的,但是如果我们认为std::swap(x, x)在C++ 98中应该是安全的,那么这也意味着C++ std::swap11/14可以默默地破坏C++ 98代码.

所以std::swap(x, x)保证x保持不变?在C++ 98中?在C++ 11中?如果是,那么它如何与17.6.4.9的移动分配许可相互作用而不是自我分配安全的?

c++ swap c++11

24
推荐指数
1
解决办法
1568
查看次数

Copy-and-Swap Idiom应该成为C++ 11中的复制和移动习惯吗?

本回答所述,复制和交换习惯用法如下实现:

class MyClass
{
private:
    BigClass data;
    UnmovableClass *dataPtr;

public:
    MyClass()
      : data(), dataPtr(new UnmovableClass) { }
    MyClass(const MyClass& other)
      : data(other.data), dataPtr(new UnmovableClass(*other.dataPtr)) { }
    MyClass(MyClass&& other)
      : data(std::move(other.data)), dataPtr(other.dataPtr)
    { other.dataPtr= nullptr; }

    ~MyClass() { delete dataPtr; }

    friend void swap(MyClass& first, MyClass& second)
    {
        using std::swap;
        swap(first.data, other.data);
        swap(first.dataPtr, other.dataPtr);
    }

    MyClass& operator=(MyClass other)
    {
        swap(*this, other);
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

通过将MyClass的值作为operator =的参数,可以通过复制构造函数或移动构造函数构造参数.然后,您可以安全地从参数中提取数据.这可以防止代码重复并有助于异常安全.

答案提到您可以在临时中交换或移动变量.它主要讨论交换.但是,交换(如果未由编译器优化)涉及三个移动操作,而在更复杂的情况下,还需要额外的额外工作.当你想要的时候,就是临时文件移动到assign-to对象中.

考虑这个更复杂的例子,涉及观察者模式.在这个例子中,我手动编写了赋值运算符代码.重点是移动构造函数,赋值运算符和交换方法:

class MyClass : Observable::IObserver …
Run Code Online (Sandbox Code Playgroud)

c++ assignment-operator move-semantics copy-and-swap c++11

23
推荐指数
3
解决办法
4942
查看次数

标准库中自我赋值 - 不安全移动赋值运算符的基本原理是什么?

关于移动分配的标准库策略是允许实现假设永远不会发生自我分配 ; 在我看来这是一个非常糟糕的主意,因为:

  • C++中的"常规"("复制")转让合同一直被认为是安全的,不能自我分配; 现在我们还有另一个C++记忆和解释的不连贯的角落案例 - 以及一个微妙危险的案例; 我想我们都同意C++中需要的不是更隐藏的陷阱;
  • 它使算法复杂化 - remove_if家庭中的任何事情都需要照顾这个角落的情况;
  • 实现这个要求真的很容易 - 你用swap实现移动它是免费的,甚至在其他情况下(你可以通过ad-hoc逻辑获得一些性能提升)它只是一个,(几乎)从不采取分支,在任何CPU¹上几乎是免费的; 此外,在大多数有趣的情况下(涉及参数或本地的移动),优化器在内联时将完全删除分支(对于"简单"移动赋值运算符几乎总是会发生这种情况).

那么,为什么这样的决定呢?


¹特别是在库代码中,实现者可以自由地利用关于"分支预期结果"的编译器特定提示(在VC++ __builtin_expect中的gcc/__assume中).

c++ move-semantics c++11 move-assignment-operator

13
推荐指数
2
解决办法
953
查看次数

在C++ 11中实现复制和交换习惯用法的更好方法

我看到许多代码在复制和交换方面实现了五个规则,但我认为我们可以使用移动函数来替换交换函数,如下面的代码所示:

#include <algorithm>
#include <cstddef>

class DumbArray {
public:
    DumbArray(std::size_t size = 0)
        : size_(size), array_(size_ ? new int[size_]() : nullptr) {
    }

    DumbArray(const DumbArray& that)
        : size_(that.size_), array_(size_ ? new int[size_] : nullptr) {
        std::copy(that.array_, that.array_ + size_, array_);
    }

    DumbArray(DumbArray&& that) : DumbArray() {
        move_to_this(that);
    }

    ~DumbArray() {
        delete [] array_;
    }

    DumbArray& operator=(DumbArray that) {
        move_to_this(that);
        return *this;
    }

private:
    void move_to_this(DumbArray &that) {
        delete [] array_;
        array_ = that.array_;
        size_ = that.size_;
        that.array_ = nullptr;
        that.size_ …
Run Code Online (Sandbox Code Playgroud)

c++ c++11

11
推荐指数
2
解决办法
2288
查看次数

在C++ 11中编写Copy/Move/operator = trio的"正确"方法是什么?

此时,编写复制构造函数和赋值运算符对是明确定义的; 快速搜索将引导您充分了解如何正确编码这些.

既然移动构造函数已进入组合,是否有一种新的"最佳"方式?

c++ c++11

9
推荐指数
2
解决办法
762
查看次数

移动分配给自己的行为

示例代码:

#include <iostream>

int main()
{   
    std::vector<int> w(20, 123), x;
    w = std::move(w);
    std::cout << w.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

g ++ 4.8.3上的输出: 0

当然,标准说移动赋值运算符使操作数处于未指定状态.例如,如果代码是x = std::move(w);那么我们期望w.size()为零.

但是,是否有指定的排序或其他条款涵盖自动案件?是否未指定大小是否为020其他内容或未定义的行为?标准容器在这里有任何定义的语义吗?

相关:此线程讨论您是否应该关心自己的类中的自动移动,但不讨论标准容器的移动赋值运算符是否执行,并且不提供标准引用.

NB.这与功能完全相同w = static_cast< std::vector<int> && >(w);std::move不同吗?

c++ move-semantics

8
推荐指数
1
解决办法
1689
查看次数

我们需要移动和复制分配吗?

对于课程A,我们可以使用

A& operator=( A other ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

代替

A& operator=( const A&  other ) { /* ... */ }
A& operator=( const A&& other ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

没有恶化的表现或其他负面影响?

c++ assignment-operator move-semantics c++11

3
推荐指数
2
解决办法
244
查看次数

移动构造函数中的深拷贝

我是 C++11 的新手,所以我仍然在努力解决它的概念。

这是我的问题:

我有一个矩阵类:

class matrix
{

private:

  double** data;
  size_t number_lines;
  size_t number_columns;

  size_t capacity_lines;
  size_t capacity_columns;

public:
....

}
Run Code Online (Sandbox Code Playgroud)

我提供了一个复制构造函数,一个移动构造函数......

我重载了乘法运算符 *(double x) 以将矩阵元素乘以标量 x 并返回相乘后的矩阵。这是代码:

matrix matrix::operator*(double lambda)
{
double** aux_data = new double*[number_lines];
for (size_t i = 0; i < number_lines; i++)
{
    aux_data[i] = new double[number_columns];
    for (size_t j = 0; j < number_columns; j++)
        aux_data[i][j] = lambda*data[i][j];
}
return matrix(aux_data, number_lines, number_columns);
}
Run Code Online (Sandbox Code Playgroud)

函数的返回是一个右值引用,因此它调用移动构造函数。这是移动构造函数的代码:

matrix::matrix(const matrix&& moved_copy)
{
if (this != &moved_copy) 
{ …
Run Code Online (Sandbox Code Playgroud)

c++ c++11

3
推荐指数
1
解决办法
1509
查看次数

对象的赋值运算符

我编写了一个代码,用于动态分配名称.我知道我应该在这种情况下处理深层复制.我写的是我自己的Copy Constructor,Copy Assignment Operator和析构函数.我应该重新定义任何其他隐式函数,例如移动赋值运算符.我不清楚Move Assignment Operator的概念或任何其他隐式定义的成员函数(除了我已经提到的).任何人都可以为此添加代码dynName code,以显示移动赋值运算符或任何其他隐式成员函数(如果有).

#include <iostream>

using namespace std;

class dynName{
    char* name;
    int size;
    public:

    dynName(char* name="")
    {
        int n=strlen(name)+1;
        this->name= new char[n];
        strncpy(this->name,name,n);
        size=n;
        name[size-1]='\0';//NULL terminated
        cout << "Object created (Constructor) with name : "
        << name << " at address " << &(this->name) << endl;
        }

    dynName(const dynName& Ob)//Copy Constructor
    {
        int n=Ob.size;
        this->name= new char[n];
        strncpy(this->name,Ob.name,n);
        size=n;
        cout << "Object created(Copy constructor) with name : "
        << this->name  << " …
Run Code Online (Sandbox Code Playgroud)

c++ class operator-overloading assignment-operator

0
推荐指数
1
解决办法
289
查看次数