首页 > 解决方案 > 避免通过 std::transform 进行复制构造

问题描述

我用一个 lambda 调用 std::transform ,它通过引用获取并返回对向量元素的引用。但是,根据我的程序输出,调用了复制构造函数并且对象不一样。

代码

#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

所以我现在还不清楚三件事:

  1. 为什么对象不同?他们不应该是一样的吗?
  2. 为什么一个对象的地址比另一个大?这是因为复制到的对象保留在具有偏移指针的堆栈上吗?
  3. 我怎样才能避免复制构造(实际上我只是“误用” std::transform 以声明性方式在每个 std::vector 元素上调用 lambda)?

标签: c++referencestd

解决方案


副本与您使用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";
}

推荐阅读