c++ vector 中 push_back emplace_back 的区别
vector 中的 push_back 和 emplace_back 都是用于在 vector 的末尾添加元素的方法。它们的主要区别在于传递参数的方式。
push_back 接受一个对象的副本或一个右值引用,并将其添加到 vector 的末尾。如果对象是一个临时对象或右值引用,那么它将被移动到 vector 中,这意味着它的资源所有权将被转移给 vector,而不是被复制到 vector 中。
emplace_back 接受构造函数的参数,并在 vector 的末尾直接构造一个新的对象。这意味着在使用 emplace_back 时,不需要创建对象的副本,也不需要将对象移动到 vector 中。相反,vector 可以直接在其内存中构造新对象,这可以提高性能并减少内存分配的次数。
因此,如果你已经有了一个对象并想将其添加到 vector 中,那么你应该使用 push_back。如果你需要构造一个新对象并将其添加到 vector 中,则应该使用 emplace_back。
c++ vector 中 push_back emplace_back 的区别
vector 的 push_back 和 emplace_back 都是用于在 vector 末尾添加元素的方法,它们的区别在于传递参数的方式。
push_back 接受一个对象的副本或右值引用,并将其添加到 vector 的末尾。如果对象是右值引用或临时对象,那么它将被移动到 vector 中,这意味着它的所有权将被转移给 vector,而不是被复制到 vector 中。
emplace_back 接受构造函数的参数,并在 vector 的末尾直接构造一个新的对象。这意味着在使用 emplace_back 时,不需要创建对象的副本,也不需要将对象移动到 vector 中。相反,vector 可以直接在其内存中构造新对象,这可以提高性能并减少内存分配的次数。
因此,如果你已经有了一个对象并想将其添加到 vector 中,那么你应该使用 push_back。如果你需要构造一个新对象并将其添加到 vector 中,则应该使用 emplace_back。如果你的对象是一个简单的类型(如 int、float 等),那么使用 push_back 和 emplace_back 的性能差异较小,但是对于复杂类型(如自定义类或结构体),使用 emplace_back 可能会更快,因为它避免了对象的拷贝或移动。
下面是一个使用 push_back 和 emplace_back 的例子:
#include <iostream>
#include <vector>
using namespace std;
class Person {
public:
Person(string name, int age) : m_name(name), m_age(age) {
cout << "Constructing " << m_name << endl;
}
~Person() {
cout << "Destructing " << m_name << endl;
}
private:
string m_name;
int m_age;
};
int main() {
vector<Person> people;
// 使用 push_back 添加一个 Person 对象
Person p1("Alice", 20);
people.push_back(p1);
// 使用 emplace_back 添加一个 Person 对象
people.emplace_back("Bob", 30);
// 输出 vector 中的元素
for (const auto& p : people) {
cout << p << endl;
}
return 0;
}
这个例子中,我们使用 push_back 和 emplace_back 分别添加了两个 Person 对象到 vector 中。其中,push_back 接受一个 Person 对象的副本,而 emplace_back 接受构造函数的参数并在 vector 中直接构造一个新的 Person 对象。输出结果如下:
Constructing Alice
Constructing Bob
Alice, 20
Bob, 30
Destructing Alice
Destructing Bob
我们可以看到,在使用 push_back 时,Person 对象会被复制到 vector 中,而在使用 emplace_back 时,Person 对象会在 vector 中直接构造。另外,我们还打印了每个 Person 对象的名字和年龄,以及它们的构造和析构函数的调用。
为什么会调用 2 次析构函数?#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Person {
public:
Person(string name, int age) : m_name(name), m_age(age) {
cout << "Constructing " << m_name << endl;
}
~Person() {
cout << "Destructing " << m_name << endl;
}
string to_string() const {
return "Person: " + m_name;
}
private:
string m_name;
int m_age;
};
int main() {
vector<Person> people;
// 使用 push_back 添加一个 Person 对象
Person p1("Alice", 20);
cout << "---------" << endl;
people.push_back(p1);
// 使用 emplace_back 添加一个 Person 对象
// people.emplace_back("Bob", 30);
// 输出 vector 中的元素
// for (const auto& p : people) {
// cout << p.to_string() << endl;
// }
return 0;
}
在你的代码中,当你将 Person 对象 p1 传递给 push_back 时,vector 会将其复制到 vector 的内部存储中。当 vector 的生命周期结束时,会自动调用其元素的析构函数以释放内存。因此,在程序结束时,会调用两次析构函数:一次是 p1 的析构函数,另一次是 vector 中的元素析构函数。
如果你使用 emplace_back,vector 将直接在其内存中构造一个新的 Person 对象,而不是将其复制到 vector 的内存中。在这种情况下,当 vector 的生命周期结束时,只会调用 vector 中的元素的析构函数,而不会调用 p1 的析构函数,因为 p1 并没有被添加到 vector 中。
因此,如果你只想在 vector 中存储元素的副本而不是原始对象,那么使用 push_back 是一个不错的选择。但是,如果你想在 vector 中存储原始对象并避免不必要的拷贝,那么可以使用 emplace_back。
拷贝构造函数的写法
拷贝构造函数的写法如下:
class MyClass {
public:
// 拷贝构造函数
MyClass(const MyClass& other) {
// 在这里实现拷贝构造函数的逻辑
}
};
拷贝构造函数是一种特殊的构造函数,用于在创建一个新对象时使用现有对象的副本来初始化它。当一个对象被传递给一个函数或被返回时,拷贝构造函数会被调用。它通常用于创建一个新对象,该对象的内容与现有对象相同,但是在内存中具有不同的地址。
在拷贝构造函数中,通常需要复制对象的所有成员变量,以确保新对象与原始对象相同。例如,如果对象包含指针,那么拷贝构造函数需要复制指针所指向的内容,而不是只复制指针本身。在实现拷贝构造函数时,可以使用成员初始化列表来初始化对象的成员变量。
需要注意的是,如果一个类没有显式定义拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数,该函数会将所有成员变量逐一复制到新对象中。但是,如果类包含指针或其他需要特殊处理的资源,那么可能需要实现自己的拷贝构造函数,以确保正确地复制和管理这些资源。
构造函数的种类
C++ 中的构造函数主要有以下几种类型:
默认构造函数:没有任何参数的构造函数称为默认构造函数。如果一个类没有显式定义构造函数,那么编译器会为其生成一个默认构造函数。默认构造函数用于创建对象的默认初始化。
带参构造函数:带有一个或多个参数的构造函数称为带参构造函数。带参构造函数用于在创建对象时初始化对象的成员变量。
拷贝构造函数:用于创建一个新对象并将其初始化为现有对象的副本的构造函数称为拷贝构造函数。拷贝构造函数通常用于传递和返回对象,以及在创建对象时使用已存在的对象来初始化新对象。
移动构造函数:用于创建一个新对象并将其初始化为右值对象的构造函数称为移动构造函数。移动构造函数通常用于在不必要地复制大型或昂贵的对象时提高程序的性能。
隐式构造函数:C++ 11 引入了一种新的构造函数类型,称为隐式构造函数。它可以将单个参数隐式地转换为目标类型,并用于在需要时自动将类型转换为所需类型。
需要注意的是,构造函数可以被重载,这意味着同一个类可以有多个构造函数,每个构造函数可以接受不同的参数列表。在使用重载构造函数时,需要注意避免二义性。
不同构造函数的例子
下面是一些不同构造函数的例子:
#include <iostream>
#include <string>
using namespace std;
// 默认构造函数
class Person1 {
public:
Person1() {
m_name = "";
m_age = 0;
}
void print() const {
cout << "Name: " << m_name << ", Age: " << m_age << endl;
}
private:
string m_name;
int m_age;
};
// 带参构造函数
class Person2 {
public:
Person2(string name, int age) {
m_name = name;
m_age = age;
}
void print() const {
cout << "Name: " << m_name << ", Age: " << m_age << endl;
}
private:
string m_name;
int m_age;
};
// 拷贝构造函数
class Person3 {
public:
Person3(const Person3& other) {
m_name = other.m_name;
m_age = other.m_age;
}
void print() const {
cout << "Name: " << m_name << ", Age: " << m_age << endl;
}
private:
string m_name;
int m_age;
};
// 移动构造函数
class Person4 {
public:
Person4(string name, int age) {
m_name = name;
m_age = age;
}
Person4(Person4&& other) {
m_name = move(other.m_name);
m_age = other.m_age;
}
void print() const {
cout << "Name: " << m_name << ", Age: " << m_age << endl;
}
private:
string m_name;
int m_age;
};
int main() {
// 使用默认构造函数
Person1 p1;
p1.print();
// 使用带参构造函数
Person2 p2("Alice", 20);
p2.print();
// 使用拷贝构造函数
Person3 p3(p2);
p3.print();
// 使用移动构造函数
Person4 p4("Bob", 30);
Person4 p5(move(p4));
p4.print();
p5.print();
return 0;
}
在这个例子中,我们定义了四个不同的构造函数,包括默认构造函数、带参构造函数、拷贝构造函数和移动构造函数。我们创建了四个 Person 对象,并分别使用了不同的构造函数来初始化它们。输出结果如下:
Name:
Age: 0
Name: Alice
Age: 20
Name: Alice
Age: 20
Name:
Age: 0
Name: Bob
Age: 30
我们可以看到,每个对象都被正确地初始化,并且使用了不同的构造函数。
c++ 中右值和左值的含义
An error occurred with your deployment
EDGE_FUNCTION_INVOCATION_TIMEOUT
c++ 中右值和左值的含义