- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
最佳答案
介绍
C++ 使用值语义处理用户定义类型的变量。
这意味着对象在各种上下文中被隐式复制,
我们应该理解“复制对象”的实际含义。
让我们考虑一个简单的例子:
class person
{
std::string name;
int age;
public:
person(const std::string& name, int age) : name(name), age(age)
{
}
};
int main()
{
person a("Bjarne Stroustrup", 60);
person b(a); // What happens here?
b = a; // And here?
}
(如果您对
name(name), age(age)
部分感到困惑,
person
是什么意思目的?
main
函数显示了两种不同的复制场景。
person b(a);
由复制构造函数执行。
b = a
由复制赋值运算符执行。
The [...] copy constructor and copy assignment operator, [...] and destructor are special member functions.[ Note: The implementation will implicitly declare these member functionsfor some class types when the program does not explicitly declare them.The implementation will implicitly define them if they are used. [...] end note ][n3126.pdf section 12 §1]
The implicitly-defined copy constructor for a non-union class X performs a memberwise copy of its subobjects.[n3126.pdf section 12.8 §16]
The implicitly-defined copy assignment operator for a non-union class X performs memberwise copy assignmentof its subobjects.[n3126.pdf section 12.8 §30]
person
的隐式定义的特殊成员函数看起来像这样:
// 1. copy constructor
person(const person& that) : name(that.name), age(that.age)
{
}
// 2. copy assignment operator
person& operator=(const person& that)
{
name = that.name;
age = that.age;
return *this;
}
// 3. destructor
~person()
{
}
在这种情况下,成员复制正是我们想要的:
name
和
age
被复制,所以我们得到一个独立的,独立的
person
目的。
person
之后被隐式调用析构函数完成:
After executing the body of the destructor and destroying any automatic objects allocated within the body,a destructor for class X calls the destructors for X's direct [...] members[n3126.pdf 12.4 §6]
std::string
这样的东西,而程序员则爱上了指针。
person
类可能看起来像这样:
class person
{
char* name;
int age;
public:
// the constructor acquires a resource:
// in this case, dynamic memory obtained via new[]
person(const char* the_name, int the_age)
{
name = new char[strlen(the_name) + 1];
strcpy(name, the_name);
age = the_age;
}
// the destructor must release this resource via delete[]
~person()
{
delete[] name;
}
};
即使在今天,人们仍然以这种方式编写类并陷入困境:
name
成员只是复制一个指针,而不是它指向的字符数组!
a
更改可以通过 b
观察. b
被摧毁,a.name
是一个悬空指针。 a
被破坏,删除悬空指针产生 undefined behavior . name
在分配之前指出,// 1. copy constructor
person(const person& that)
{
name = new char[strlen(that.name) + 1];
strcpy(name, that.name);
age = that.age;
}
// 2. copy assignment operator
person& operator=(const person& that)
{
if (this != &that)
{
delete[] name;
// This is a dangerous point in the flow of execution!
// We have temporarily invalidated the class invariants,
// and the next statement might throw an exception,
// leaving the object in an invalid state :(
name = new char[strlen(that.name) + 1];
strcpy(name, that.name);
age = that.age;
}
return *this;
}
注意初始化和赋值的区别:
name
之前拆除旧状态以防止内存泄漏。
x = x
的自赋值。 .
delete[] name
将删除包含源字符串的数组,
x = x
, 两者
this->name
和
that.name
包含相同的指针。
new char[...]
,此解决方案将失败由于内存耗尽而引发异常。
// 2. copy assignment operator
person& operator=(const person& that)
{
char* local_name = new char[strlen(that.name) + 1];
// If the above statement throws,
// the object is still in the same state as before.
// None of the following statements will throw an exception :)
strcpy(local_name, that.name);
delete[] name;
name = local_name;
age = that.age;
return *this;
}
这也可以在没有明确检查的情况下处理自分配。
private
没有给出定义:
private:
person(const person& that);
person& operator=(const person& that);
或者,您可以从
boost::noncopyable
继承或将它们声明为已删除(在 C++11 及更高版本中):
person(const person& that) = delete;
person& operator=(const person& that) = delete;
规则三
If you need to explicitly declare either the destructor,copy constructor or copy assignment operator yourself,you probably need to explicitly declare all three of them.
class person
{
std::string name;
int age;
public:
person(const std::string& name, int age); // Ctor
person(const person &) = default; // 1/5: Copy Ctor
person(person &&) noexcept = default; // 4/5: Move Ctor
person& operator=(const person &) = default; // 2/5: Copy Assignment
person& operator=(person &&) noexcept = default; // 5/5: Move Assignment
~person() noexcept = default; // 3/5: Dtor
};
零的法则
std::string
已经为你做了。
std::string
比较简单的代码成员
char*
的复杂且容易出错的替代方案你应该被说服。
关于c++ - 三分法则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4172722/
在 SO解释了为什么像 scalaz、cats (Scala) 或 Arrow (Kotlin) 中的 Validation 不能是 monad。 据我所知,这是因为他们已经根据应用仿函数对 mona
给定例如像 这样的类型 data Tree a = Branch (Tree a) (Tree a) | Leaf a 我可以轻松地为 Functor、Applicative、
从这里引用:https://en.wikipedia.org/wiki/Law_of_Demeter More formally, the Law of Demeter for functions r
以下代码打破了 Law of Demeter : public class Student extends Person { private Grades grades; public Stu
我有一个简单的 Store 类,其中包含一个 Inventory。 Inventory 包含一个 Item 列表。为了修改 Inventory 中的其中一个 Item,我必须这样写: Store st
public class BigPerformance { public decimal Value { get; set; } } public class Performance
当我需要多态行为时,我经常发现自己在 C++ 中使用唯一指针。我通常实现如下所示的纯抽象类: class A { public: virtual A* clone() const = 0; /
5 规则指出,如果一个类有一个用户声明的析构函数、复制构造函数、复制赋值构造函数、移动构造函数或移动赋值构造函数,那么它必须有其他 4 个。 但今天我突然明白了:你什么时候需要用户定义的析构函数、复制
编译器或库的更“ native ”部分(IO 或可以访问黑魔法和实现的函数)是否对这些定律做出假设?打破它们会导致不可能的事情发生吗? 或者它们只是表达了一种编程模式——也就是说,你唯一会因为破坏它们
我有点想用 Java 8 流编写 Selenium 页面对象,如下面的代码所述,并收到评论说我的代码违反了 Demeter 法则,因为我在一行中执行了很多操作。我被建议将代码分解为第一个流以收集列表并
我对如何避免一对多关联违反得墨忒耳法则感到困惑。假设我有一个这样的模型: class Organization < ActiveRecord::Base has_one :address ha
如果我有一个对象的 ArrayList,那么任何时候我需要调用 ArrayList 成员的任何方法时,我都需要这样做: list.get(i).doSomething(); 这看起来很可疑地违反了 D
我在我的 Purescript 代码中广泛使用了来自库和我自己的类型类。每个类型类法则似乎都提供了一个很好的测试。目前,我正在为每个类(class)和法律单独编写测试。有没有办法部分自动化?也许像 H
我看到提到过 ListT is a classic example of a buggy monad transformer that doesn't satisfy the monad laws.
当我审查一些代码时,我看到了这个片段。 List users = /* Some code that initializes the list */; users.stream() .fil
我是一名优秀的程序员,十分优秀!