这不是根据operator =实现复制构造函数的重复,而是一个更具体的问题.(或者我喜欢思考.)
介绍
鉴于这样的(假设的)类:
struct FooBar {
long id;
double valX;
double valZ;
long valN;
bool flag;
NonCopyable implementation_detail; // cannot and must not be copied
// ...
};
Run Code Online (Sandbox Code Playgroud)
我们无法通过默认生成的函数复制它,因为您既不能复制构造也不能复制NonCopyable对象.但是,这部分对象是我们实际上对复制不感兴趣的实现细节.
为此编写交换函数也没有任何意义,因为交换函数可以复制std :: swap的作用(减去NonCopyable).
因此,如果我们想要复制这些对象,我们就会自己实现copy-ctor和copy-operator.只需分配其他成员即可完成.
题
如果我们需要实现copy ctor和operator,我们是应该根据copy运算符实现copy ctor,还是应该用初始化列表"复制"代码?
那是,给定:
FooBar& operator=(FooBar const& rhs) {
// no self assignment check necessary
id = rhs.id;
valX = rhs.valX;
valZ = rhs.valZ;
valN = rhs.valN;
flag = rhs.flag;
// don't copy implementation_detail
return *this;
}
Run Code Online (Sandbox Code Playgroud)
我们应该写一个)
FooBar(FooBar const& …Run Code Online (Sandbox Code Playgroud) 例如:
class Derived : public Base
{
Derived(const Base &rhs)
{
// Is this a copy constructor?
}
const Derived &operator=(const Base &rhs)
{
// Is this a copy assignment operator?
}
};
Run Code Online (Sandbox Code Playgroud)
我试图了解副本分配构造函数在c ++中的工作方式。我只使用过Java,所以我真的不在这里。我已经阅读并看到返回引用是一种很好的做法,但是我不知道该怎么做。我写了这个小程序来测试这个概念:
main.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main() {
Test t1,t2;
t1.setAge(10);
t1.setId('a');
t2.setAge(20);
t2.setId('b');
cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";
t2 = t1; // calls assignment operator, same as t2.operator=(t1)
cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";
Test t3 = t1; // copy constr, same as Test t3(t1)
cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << …Run Code Online (Sandbox Code Playgroud) 来自c ++背景我很好奇Ruby中的对象赋值.应对以下对象分配进行哪些考虑(如果有):
class MyClass
attr_accessor :a, :b
def initialize(a, b)
@a = a
@b = b
end
def some_method
puts "#{self.a} #{self.b}"
end
end
m = MyClass.new("first", "last")
n = MyClass.new("pizza", "hello")
q = n
q.some_method
Run Code Online (Sandbox Code Playgroud) 当我在D中分配一个对象时,它会被复制吗?
void main() {
auto test = new Test(new Object());
tset.obj;
}
class Test {
public Object obj;
public this(Object ref origObj) {
obj = origObj; // Will this copy origObj into obj, or will origObj and obj point to the same data? (Is this a valid way to pass ownership without copying the object?)
}
}
Run Code Online (Sandbox Code Playgroud) noexcept复制构造函数和复制赋值运算符?如果可能,请提供参考.尝试编写允许拦截/否决修改的通用包装时会出现问题.我能提出的任何实现都可能会改变底层容器的语义,除非专门针对每个容器类型(这不是一个真正的选项).
例如,std::vector有一个填充插入:
void insert (iterator position, size_type n, const value_type& val);
Run Code Online (Sandbox Code Playgroud)
这需要value_type同时是CopyInsertable和CopyAssignable.需要注意的是它并没有要求值类型为缺省构造.
编辑3 Stroustrup本人(第956页的表)表明多元素插入应该对所有向量,双端队列,列表和映射具有强大的保证.这意味着完整的标准库操作要么原子成功要么失败.
编辑4但是,保证仅适用于相关操作(在本例中为复制构造函数)本身不会抛出异常,这正是我的问题.
据我了解,这留下了两个基本的实现方法:
val.这只有在可以通过复制容器中的现有元素或者何时value_type是DefaultConstructible(这不是必需的)创建虚拟元素时才有效.编辑2:我不会调用这种未定义的行为,因为该术语似乎会使人们认为未定义为语言运行时/标准.
当复制构造函数或复制赋值运算符引发异常时,这两种实现似乎都会使容器具有未知内容(即,在异常之后不清楚容器占用哪些元素).
编辑1:请注意,这并不意味着我认为C++运行时存在不良行为,例如内存泄漏或未定义的值.但是,似乎或多或少未指明容器的内容是什么.特别是,容器的内容可能已完全(尽管一直)改变.
例如,考虑第三种(混合)方法:
n模板对象的副本列表val.不同之处在于复制构造函数引发异常时对容器的影响.在这种情况下,如果复制构造函数抛出(但在复制赋值运算符抛出时仍会导致未指定的内容),则容器的内容保持不变.当使用指针(即不使用时std::vector)时,可能会遗漏复制分配,只重新排列指针,使操作原子化.例外.
至于noexcept容器元素:对象是通过创建的 …
在容器中具有这些特征的原因是什么(https://en.cppreference.com/w/cpp/memory/allocator_traits)
propagate_on_container_copy_assignment Alloc::propagate_on_container_copy_assignment if present, otherwise std::false_type
propagate_on_container_move_assignment Alloc::propagate_on_container_move_assignment if present, otherwise std::false_type
propagate_on_container_swap Alloc::propagate_on_container_swap if present, otherwise std::false_type
Run Code Online (Sandbox Code Playgroud)
is_always_equal(since C++17) Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
Run Code Online (Sandbox Code Playgroud)
我知道容器实现在分配和交换的实现中会以一种或另一种方式表现。(并且处理这些情况是可怕的代码。)我也明白有时人们可能需要将移动容器保持在一种状态resizeble或者至少可以调用一些最后的释放,因此分配器不能无效。(我个人认为这是一个弱论点。)
但问题是, 为什么这些信息不能成为自定义分配器类型本身的正常实现和语义的一部分?
我的意思是,容器复制分配可以尝试复制分配源分配器,如果语法复制分配没有真正复制,那么,就像说你的容器没有 propagate_on_container_copy_assignment。
以同样的方式而不是使用 is_always_equal一个实际上可以使分配器分配什么也不做。
(此外,如果is_always_equal为真,则可以让operator==分配器返回std::true_type以发出信号。)
在我看来,这些特征似乎试图覆盖可以通过普通 C++ 方式提供给自定义分配器的语义。这似乎与泛型编程和当前的 C++ 哲学背道而驰。
唯一的原因,我认为这对于实现与“旧”容器的某种向后兼容性很有用。
如果我今天要编写一个新容器和/或一个新的非平凡分配器,我可以依靠分配器的语义而忘记这些特征吗?
在我看来,只要移动的分配器可以“解除分配”一个空指针状态(这意味着在这种特殊情况下主要是什么都不做),那么它应该没问题,如果resize抛出,那也很好(有效) ,这只是意味着分配器无法再访问其堆。
编辑:实际上, 我可以这样简单地编写容器吗?并将复杂性委托给自定义分配器的语义?:
templata<class Allocator>
struct my_container{
Allocator alloc_;
...
my_container& operator=(my_container const& other){ …Run Code Online (Sandbox Code Playgroud) allocator move-semantics copy-assignment c++11 move-assignment-operator
首先,我真的检查了是否已经有人问过一个问题,但我找不到任何问题。错误消息不应该欺骗你我的情况有点不同我猜或者我只是错过了一些东西。
当我处理一个玩具 C++ 代码时,我遇到了一个奇怪的错误。程序输出说有双重空闲情况,但我看不到发生此错误的地方。代码可能看的有点长,对此我深表歉意。
我现在正在工作Linux Distribution,我正在使用g++ 9.1.0. 我检查了我的代码并寻找错误的部分。
即使我固定的一些代码的一部分,我的问题没有得到解决,当我发表评论或者除了Foo{1, "Hello World"};或者vec.push_back(std::move(Foo{}));,我不为什么得到它。
class Foo
{
public:
Foo()
: val{nullptr}, str{nullptr}
{
std::cout << "You are in empty constructor\n";
}
Foo(int the_val, const char *the_str)
: val{new int}, str{new char[std::strlen(the_str + 1)]}
{
*val = the_val;
std::cout << *val << '\n';
std::strcpy(str, the_str);
std::cout << str << '\n';
}
~Foo()
{
if (val) {
delete val;
} else {
std::cout << "val is empty\n"; …Run Code Online (Sandbox Code Playgroud) c++ move-constructor construct copy-assignment move-assignment-operator
在这个 C++ 示例中,一个类C有一个默认构造函数、一个复制构造函数和一个赋值运算符:
struct C {
C();
C(const C& c);
C& operator=(const C& c);
};
Run Code Online (Sandbox Code Playgroud)
实现如下,带有一些用于跟踪对象的输出。我在注释中添加了一些示例地址作为对main下面程序的参考。
#include "C.h"
#include <iostream>
using namespace std;
C::C() {
cout << "Standard constructor." << endl;
}
C::C(const C& c) {
cout << "Copy constructor." << endl;
}
C& C::operator=(const C& c) {
cout << "Address of reference argument: &c = " << &c << endl; // F9B4
cout << "Address of this: &*this = " << &*this << endl; // …Run Code Online (Sandbox Code Playgroud) c++ class memory-address assignment-operator copy-assignment