16

我不确定我使用的术语是否正确,但问题是如何正确创建一个将字符串作为参数的构造函数?

我习惯于const char *在构造函数中使用 a 而不是字符串。

通常我会做这样的事情:

Name(const char* fName, const char* lName)
    : firstName(0), lastName(0)
{
    char * temp = new char [strlen(fName) + 1];
    strcpy_s(temp, strlen(fName) + 1, fName);
    firstName = temp;

    char * temp2 = new char [strlen(lName) + 1];
    strcpy_s(temp2, strlen(lName) + 1, lName);
    lastName = temp2;
}

如果构造函数是这样的:

 Name(const string fName, const string lName) { }

我还要进行基本成员初始化吗?我还需要在构造函数的基础中使用字符串副本吗?

4

4 回答 4

15

Use std::string and initializer lists:

std::string fName, lName;

Name(string fName, string lName):fName(std::move(fName)), lName(std::move(lName))
{
}

In this case, you don't need to use terribly bare pointers, you don't need allocate memory, copy characters and finally de-allocate. In addition, this new code has chances to take advantages of moving rather than copying since std::string is movable. Also it's useful to read this.

And so on....

于 2013-11-05T23:13:39.277 回答
14

我看到您已经接受了答案,但我想扩展答案。

正如 deepmax 所说,如果您按值传递,则可以编写构造函数以利用“移动语义”。这意味着可以将数据从一个变量移动到另一个变量,而不是复制数据。

像这样写:

class Name{
    public:
        Name(std::string var): mem_var(std::move(var)){}

        std::string mem_var;
};

这似乎是个好主意,但实际上并不比复制构造函数更有效

class Name{
    public:
        Name(const std::string &var): mem_var(var){}

        std::string mem_var;
};

这是因为在一般用例中看起来像这样:

auto main() -> int{
    Name name("Sample Text");
}

无论哪种方式,都只会制作一个副本(请参阅复制省略),而在另一种情况下

auto main() -> int{
    std::string myname = "Hugh Jaynus";
    Name name(myname);
}

将以“高效”的值传递移动语义方式制作 2 个副本!

这是什么时候应该使用复制构造函数(或传递引用)的一个很好的例子,而不是一个反对它的例子。


相反...

如果您编写一个使用移动语义的显式构造函数,无论在何种情况下,您都可以获得有效的解决方案。

以下是您可以使用两个构造函数编写名称类定义的方法:

class Name{
    public:
        Name(const std::string &first_, const std::string &last_)
            : first(first_), last(last_){}

        Name(std::string &&first_, std::string &&last_) // rvalue reference
            : first(std::move(first_)), last(std::move(last_)){}

        std::string first, last;
};

然后,当您使用该类时,应该采用更有效的路径。

如果我们回到我们的示例,我们可以重写它们以使用最好或最有效的构造函数:

int main(){
    // pass by reference best here
    Name myname("Yolo", "Swaggins");

    // move most efficient here
    // but never use 'first' and 'last' again or UB!
    std::string first = "Hugh", last = "Jaynus";
    Name yourname(std::move(first), std::move(last));
}

永远不要想当然地认为一种解决方案比所有其他解决方案都好!

于 2015-06-30T04:47:56.630 回答
3

我习惯这样做:

std::string fName;
std::string lName;

Name(const std::string &fName, const std::string &lName) :
     fName(fName), lName(lName)
{
}

使用引用节省了将字符串复制到堆栈上的新对象的工作,它只会将引用传递给现有字符串。将它们分配给班级成员后,它们将被复制。

于 2013-11-05T23:17:29.023 回答
0

如果您想保留 const char * 作为构造函数输入类型,请执行此操作。

std::string fName;
std::string lName;

Name(const char *_fName, const char *_lName) :
     fName(_fName), lName(_lName)
{
}

您可以从 const char 构造 std::string。

于 2013-11-06T05:30:47.057 回答