通过 std::transform 避免复制构造
Avoid copy construction by std::transform
我正在调用 std::transform 时使用一个 lambda,它通过引用获取并返回对向量元素的引用。但是,根据我的程序输出,调用了复制构造函数并且对象不一样。
代码:
#include <algorithm>
#include <iostream>
#include <vector>
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
}
输出(神马):
Object constructed with 5
Object constructed with 10
Copy constructor, our address: 0x23d7ec0, his address: 0x7fff9dc499a8
Copy constructor, our address: 0x23d7ec4, his address: 0x7fff9dc499ac
所以我现在不清楚三件事:
- 为什么对象不同?他们不应该是一样的吗?
- 为什么一个对象的地址比另一个大?这是因为复制到的对象保留在具有偏移指针的堆栈上吗?
- 我怎样才能避免复制构造(实际上我只是“误用”std::transform 作为在每个 std::vector 元素上调用 lambda 的声明方式)?
副本与您对 std::transform
的使用无关。它们在您构造 v_math
std::vector
时发生,因为您使用的是 std::initializer_list
构造函数,它在构造期间强制复制。
在您的 std::transform
调用中,调用了 operator=(const Math&)
,请将您的代码更改为以下内容以查看此内容。
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
Math& operator=(const Math& other) {
val_ = other.val_;
std::cout << "Operator=(const Math&) called!\n";
return *this;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::cout << "After constructing v_math!\n";
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
std::cout << "After std::transform call!\n";
}
我正在调用 std::transform 时使用一个 lambda,它通过引用获取并返回对向量元素的引用。但是,根据我的程序输出,调用了复制构造函数并且对象不一样。
代码:
#include <algorithm>
#include <iostream>
#include <vector>
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
}
输出(神马):
Object constructed with 5
Object constructed with 10
Copy constructor, our address: 0x23d7ec0, his address: 0x7fff9dc499a8
Copy constructor, our address: 0x23d7ec4, his address: 0x7fff9dc499ac
所以我现在不清楚三件事:
- 为什么对象不同?他们不应该是一样的吗?
- 为什么一个对象的地址比另一个大?这是因为复制到的对象保留在具有偏移指针的堆栈上吗?
- 我怎样才能避免复制构造(实际上我只是“误用”std::transform 作为在每个 std::vector 元素上调用 lambda 的声明方式)?
副本与您对 std::transform
的使用无关。它们在您构造 v_math
std::vector
时发生,因为您使用的是 std::initializer_list
构造函数,它在构造期间强制复制。
在您的 std::transform
调用中,调用了 operator=(const Math&)
,请将您的代码更改为以下内容以查看此内容。
class Math
{
private:
int val_ = 5;
public:
Math(const Math& m) {
std::cout << "Copy constructor, our address: " << this << ", his address: " << &m << std::endl;
}
Math(int val) : val_(val) {
std::cout << "Object constructed with " << val << std::endl;
}
Math& operator=(const Math& other) {
val_ = other.val_;
std::cout << "Operator=(const Math&) called!\n";
return *this;
}
};
int main()
{
std::vector<Math> v_math = { { 5 }, { 10 } };
std::cout << "After constructing v_math!\n";
std::transform(
begin(v_math),
end(v_math),
begin(v_math),
[](const Math& m)-> const Math& {
return m;
});
std::cout << "After std::transform call!\n";
}