【问题标题】:Why doesn't my copy constructor work?为什么我的复制构造函数不起作用?
【发布时间】:2013-08-24 09:39:39
【问题描述】:

这可能很简单,但我有点难过。我的vectors not behaving nicely 遇到了一些问题,现在看来我找到了罪魁祸首。这是我的Player 课程的淡化版本。

class Player {
private:
    std::string _firstName;
    std::string _lastName;
public:
    Player(std::string firstName, std::string lastName) {
        _firstName = firstName;
        _lastName = lastName;
    };
    Player(const Player& otherPlayer) {
        _firstName = otherPlayer._firstName.c_str();
        _lastName = otherPlayer._lastName.c_str();
        std::cout << "Created " << _firstName << " " << _lastName << std::endl; // Why doesn't _firstName and _lastName contain anything?
    };
    std::string GetName() { return _firstName + " " + _lastName; };
};

int main(int argc, const char * argv[])
{

    Player player1 = Player("Bill", "Clinton");
    Player player2 = Player(player1);

    std::cout << "Player: " << player2.GetName() << std::endl;

    return 0;
}

输出是微薄的Player:。我不确定为什么我的复制构造函数没有做我想要做的事情,特别是考虑到this(Zac Howland 的评论占c_str();-部分)之类的建议。我是否违反了the rule of three(顺便说一句,我还没有完全理解)?如果有人能指出正确的方向,我将不胜感激!

【问题讨论】:

  • @Zak Howland 的 cmets 是错误的。他描述了大约 10 年前的工作方式,但是 (A) 现在 std::string::operator= 需要进行深拷贝,并且 (B) 它总是需要一样进行深拷贝。
  • 您实际上根本不需要复制构造函数——默认的会做正确的事情。如果你有它,你不需要调用c_str()(它们只是让它变得不那么健壮),你应该初始化成员而不是分配给它们。但尽管如此,我看不出有任何理由说明它不应该像现在这样工作。你得到什么输出?
  • 它(咳嗽)在我的机器上工作。

标签: c++ copy-constructor stdstring


【解决方案1】:

它对我有用:http://ideone.com/aenViu

我刚刚添加了:

#include <iostream>
#include <string>

但是有一点我不明白:

_firstName = otherPlayer._firstName.c_str();
_lastName = otherPlayer._lastName.c_str();

为什么是 .c_str() ?您将string 转换为char* 以将其分配给新的string

编辑: Zac Howland 在评论中指出:“在 C++11 之前,如果你想确保你的字符串被复制(而不是引用计数),你必须使用c_str() 方法强制它复制字符串。新标准消除了这一点,但如果他使用的是较旧的编译器,或者尚未完全实现 C++11 的编译器,它将确保深拷贝。

只要做:

_firstName = otherPlayer._firstName;
_lastName = otherPlayer._lastName;

而且,你真的需要这个拷贝构造函数吗?我认为默认会做你想做的事......


另外,而不是分配成员:

Player(std::string firstName, std::string lastName) {
    _firstName = firstName;
    _lastName = lastName;
}

使用 member-initialization-list 代替:

Player(std::string firstName, std::string lastName) :
    _firstName( std::move(firstName) ),
    _lastName( std::move(lastName) )
{}

在第一种情况下,调用字符串的默认构造函数,然后调用字符串的复制赋值运算符,与直接调用复制构造函数的第二种情况相比,肯定会有(较小的)效率损失。

最后一件事,在可能的情况下,不将值作为方法参数传递,传递引用,甚至在不需要修改时传递 const 引用:

Player( const std::string& firstName, const std::string& lastName )
//      ^^^^^            ^            ^^^^^            ^
    : _firstName( firstName )  // no move here, since args are constant references
    , _lastName( lastName )
{}

Working live example 的所有修改。

【讨论】:

  • 在 C++11 之前,如果你想确保你的字符串被复制(而不是引用计数),你必须使用 c_str() 方法来强制它复制字符串。新标准消除了这一点,但如果他使用的是较旧的编译器,或者尚未完全实现 C++11 的编译器,它将确保深拷贝。
  • @ZacHowland 哦,没错!我会把它放在答案中!感谢您指出这一点!
  • @PierreFourgeaud 我想,我用我的删除(我想,在我看到你使用std::move() 后无关紧要)评论来对使用const &amp; 进行编辑激怒了你。但是现在,您能解释一下std::move() 在您的构造函数中使用const &amp; 的原因吗?
  • @Petr: std::move 在没有const &amp; 的构造函数中。由于已经制作了副本(当它们通过副本传递时),move 操作只允许 Player 实例获取这些副本的所有权(而不是创建另一个副本)。
  • @PetrBudnik 感谢您指出这一点。我该睡觉了;)谢谢 Zac 编辑我的帖子!
猜你喜欢
  • 2015-11-02
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 2018-07-17
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多