有没有办法让我可以使复制构造函数和赋值运算符的主体包含相同的代码,而实际上没有重复的代码(函数头除外)?
c++ constructor code-duplication copy-constructor assignment-operator
我读了有关复制和交换习语的有趣信息.我的问题是关于swap从另一个类继承时该方法的实现.
class Foo : public Bar
{
int _m1;
string _m2;
.../...
public:
void swap(Foo &a, Foo &b)
{
using std::swap;
swap(a._m1, b._m1);
swap(a._m2, b._m2);
// what about the Bar private members ???
}
.../...
};
Run Code Online (Sandbox Code Playgroud) 我通常对pimpl使用boost :: scoped_ptr(出于一个原因,因为如果我忘记处理复制构造函数,我就不会感到惊讶)
但是,使用模板,我不能将析构函数放在完全定义impl的cpp文件中,以满足scoped_ptr析构函数的要求.无论如何它确实有效,但我不确定它是否能够保证工作或只是偶然.有一些"最佳实践"或标准吗?scoped_ptr是非可复制类中pimpls的最佳智能指针吗?
template <class T> class C {
public:
C(){}
~C(){}
private:
boost::scoped_ptr<T> pimpl_;
};
Run Code Online (Sandbox Code Playgroud) 我最近重新访问了复制构造函数,赋值运算符,这里看到的复制交换idom: 什么是复制和交换习惯用法? 和许多其他地方 -
上面的链接是一个很好的帖子 - 但我还有一些问题 - 这些问题可以在很多地方,stackoverflow和许多其他网站上得到解答,但我没有看到很多一致性 -
1 - 您是否应该try- catch在我们为复制构造函数中的深层复制分配新内存的区域周围?(我已经看到了两种方式)
2 - 关于复制构造函数和赋值运算符的继承,何时应该调用基类函数,何时这些函数应该是虚函数?
3 - std::copy复制构造函数中复制内存的最佳方法是什么?我已经看过了memcpy,看到其他人说memcpy世界上最糟糕的事情.
考虑以下示例(感谢所有反馈),它提示了一些其他问题:
4 - 我们应该检查自我分配吗?如果是这样的话
5 - 关闭主题问题,但我看到swapped用作:
std::copy(Other.Data,Other.Data + size,Data);
应该是:
std::copy(Other.Data,Other.Data + (size-1),Data);
如果swap从'First到Last'而第0个元素是Other.Data?
6 - 为什么注释掉的构造函数不起作用(我必须将大小更改为mysize) - 假设这意味着无论我编写它们的顺序如何,构造函数将始终首先调用分配元素?
7 - 对我的实施还有其他评论吗?我知道代码没用,但我只想说明一点.
class TBar
{
public:
//Swap Function
void swap(TBar &One, TBar &Two)
{
std::swap(One.b,Two.b);
std::swap(One.a,Two.a);
}
int a;
int *b;
TBar& operator=(TBar Other)
{
swap(Other,*this);
return (*this);
}
TBar() : …Run Code Online (Sandbox Code Playgroud) 我最近在StackOverflow上读到了关于什么是复制和交换习语的答案?并且知道复制和交换习语可以
避免代码重复,并提供强大的异常保证.
但是,当我查看SGI STL deque 实现时,我发现它没有使用这个成语.我想知道为什么不,如果成语在某种程度上像一个"最佳实践"?
deque& operator= (const deque& __x) {
const size_type __len = size();
if (&__x != this) {
if (__len >= __x.size())
erase(copy(__x.begin(), __x.end(), _M_start), _M_finish);
else {
const_iterator __mid = __x.begin() + difference_type(__len);
copy(__x.begin(), __mid, _M_start);
insert(_M_finish, __mid, __x.end());
}
}
return *this;
}
Run Code Online (Sandbox Code Playgroud) 我试图用c ++创建一个动态字符串数组.当我尝试将动态字符串数组的内容显示到控制台时,我收到此错误:
Exception thrown at 0x0FD670B6 (msvcp140d.dll) in Assignment4.exe: 0xC0000005: Access violation reading location 0xDDDDDDDD.
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
DynamicStringArray.h
#pragma once
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class DynamicStringArray
{
public:
DynamicStringArray();
DynamicStringArray(DynamicStringArray &array);
~DynamicStringArray();
int getSize();
void displayContents();
void addEntry(const string &addElement);
string getEntry(int index);
int deleteEntry(const string &deleteElement);
private:
string *dynamicArray;
int size;
};
Run Code Online (Sandbox Code Playgroud)
DynamicStringArray.cpp
#include "stdafx.h"
#include "DynamicStringArray.h"
#include <string>
#include <iostream>
using namespace std;
DynamicStringArray::DynamicStringArray()
{
dynamicArray = NULL;
size = 0;
}
DynamicStringArray::DynamicStringArray(DynamicStringArray &array) …Run Code Online (Sandbox Code Playgroud) 我有以下简化的代码示例:
#include <algorithm>
#include <iostream>
using namespace std;
class ShouldBeMovedWhenSwapped
{
public:
// ShouldBeMovedWhenSwapped() = default;
// ShouldBeMovedWhenSwapped(ShouldBeMovedWhenSwapped&&) = default;
// ShouldBeMovedWhenSwapped(const ShouldBeMovedWhenSwapped&) = default;
// ShouldBeMovedWhenSwapped& operator=(ShouldBeMovedWhenSwapped&&) = default;
struct MoveTester
{
MoveTester() {}
MoveTester(const MoveTester&) { cout << "tester copied " << endl; }
MoveTester(MoveTester&&) { cout << "tester moved " << endl; }
MoveTester& operator=(MoveTester) { cout << "tester emplaced" << endl; return *this; } // must be declared if move declared
};
MoveTester tester;
};
int …Run Code Online (Sandbox Code Playgroud) C++ 11引入了一个新的rvalue引用概念.我正在某处读它,发现如下:
class Base
{
public:
Base() //Default Ctor
Base(int t) //Parameterized Ctor
Base(const Base& b) //Copy Ctor
Base(Base&& b) //Move Ctor
};
void foo(Base b) //Function 1
{}
void foo(Base& b) //Function 2
{}
int main()
{
Base b(10);
foo(b); -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
foo(Base()); -- Line 2
foo(2) ; -- Line 3
}
Run Code Online (Sandbox Code Playgroud)
现在我的理解有限,我的观察结果如下:
第1行将简单地调用复制构造函数,因为参数是左值.
在C++ 11之前的第2行会调用复制构造函数和所有那些临时复制内容,但是定义了移动构造函数,这里将调用它.
第3行将再次调用move构造函数,因为2将隐式转换为Base类型(rvalue).
请纠正并解释上述任何观察结果是否错误.
现在,这是我的问题:
我知道一旦我们移动一个物体,它的数据就会在呼叫位置丢失.所以,我在上面的例子中如何更改第2行以在foo中移动对象"b"(是否使用std :: move(b)?).
我读过移动构造函数比复制构造函数更有效.怎么样?我只能想到在移动构造函数的情况下我们在堆上有内存的情况不需要再分配.当我们在堆上没有任何内存时,这个陈述是否成立?
它是否比通过引用传递更有效(不,对吧?)?
我经常需要为“原始”资源句柄(例如文件句柄,Win32 OS句柄等)实现C ++包装。这样做时,我还需要实现move运算符,因为默认的编译器生成的操作符不会清除move-from对象,从而产生双删除问题。
在实现移动分配运算符时,我更喜欢显式调用析构函数,并使用new放置就地重新创建对象。这样,我避免了析构函数逻辑的重复。另外,我经常根据copy + move(在相关时)实现副本分配。这将导致以下代码:
/** Canonical move-assignment operator.
Assumes no const or reference members. */
TYPE& operator = (TYPE && other) noexcept {
if (&other == this)
return *this; // self-assign
static_assert(std::is_final<TYPE>::value, "class must be final");
static_assert(noexcept(this->~TYPE()), "dtor must be noexcept");
this->~TYPE();
static_assert(noexcept(TYPE(std::move(other))), "move-ctor must be noexcept");
new(this) TYPE(std::move(other));
return *this;
}
/** Canonical copy-assignment operator. */
TYPE& operator = (const TYPE& other) {
if (&other == this)
return *this; // self-assign
TYPE copy(other); // may throw
static_assert(noexcept(operator …Run Code Online (Sandbox Code Playgroud) c++ assignment-operator move-semantics move-assignment-operator
返回还是不返回,是函数的问题!或者,这真的很重要吗?
故事是这样的:我曾经写过如下代码:
Type3 myFunc(Type1 input1, Type2 input2){}
Run Code Online (Sandbox Code Playgroud)
但是最近我的项目学院告诉我,我应该尽量避免编写这样的函数,并建议通过将返回值放在输入参数中的方式进行以下操作。
void myFunc(Type1 input1, Type2 input2, Type3 &output){}
Run Code Online (Sandbox Code Playgroud)
他们让我相信这是更好更快的,因为在第一种方法中返回时有额外的复制步骤。
对我来说,我开始相信在某些情况下第二种方法更好,尤其是我有很多东西要返回或修改。例如:后面的第二行会比第一行更好更快,因为避免vecor<int>在返回时复制整个。
vector<int> addTwoVectors(vector<int> a, vector<int> b){}
void addTwoVectors(vector<int> a, vector<int> b, vector<int> &result){}:
Run Code Online (Sandbox Code Playgroud)
但是,在其他一些情况下,我无法购买。例如,
bool checkInArray(int value, vector<int> arr){}
Run Code Online (Sandbox Code Playgroud)
肯定会比
void checkInArray(int value, vector<int> arr, bool &inOrNot){}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我认为直接返回结果的第一种方法在更好的可读性方面更好。
总之,我对(强调 C++)感到困惑:
编辑:我知道,在某些情况下,我们必须使用其中之一。例如,return-type functions如果我需要实现method chaining. 因此,请关注两种方法都可以实现目标的情况。
我知道这个问题可能没有单一的答案或确定的事情。此外,它似乎这个决定需要在许多编码语言来进行,比如C,C++等于是任何意见或建议,非常感谢(更好的例子)。
c++ ×10
c++11 ×2
constructor ×2
inheritance ×2
arrays ×1
boost ×1
deep-copy ×1
dynamic ×1
function ×1
idioms ×1
move ×1
performance ×1
pimpl-idiom ×1
return ×1
scoped-ptr ×1
stl ×1
string ×1
templates ×1