C++ 写入运算符+;使用右值
我一直在编写自己的字符串类,考虑到我可以将右值传递给它,我不确定如何正确编写运算符+C++ 写入运算符+;使用右值,c++,visual-c++,C++,Visual C++,我一直在编写自己的字符串类,考虑到我可以将右值传递给它,我不确定如何正确编写运算符+ String operator+(String &&lhs, String &&rhs); String operator+(String& lhs,String&&rhs); String operator+(String&&lhs,String&rhs); 然而,我不知道如何实施它们。任何帮助都将不胜感激。首先,请确保在字符串
String operator+(String &&lhs, String &&rhs);
String operator+(String& lhs,String&&rhs);
String operator+(String&&lhs,String&rhs);
然而,我不知道如何实施它们。任何帮助都将不胜感激。首先,请确保在
字符串类中定义复制和移动构造函数:
class String
{
private:
char *m_data;
std::size_t m_length;
...
public:
String();
String(const String &src);
String(String &&src);
~String();
...
};
然后为类定义operator+
和operator+=
:
class String
{
public:
...
String& operator+=(const String &rhs);
...
friend String operator+(String lhs, const String &rhs)
{
lhs += rhs;
return lhs;
}
};
通过将常量字符串&
作为右侧的输入,它将处理左值和右值输入
对于操作符+
,左边是值,因此编译器可以根据输入是左值(复制)还是右值(移动)来决定要使用的最佳构造函数
或者,您可以将其实现为在左侧使用常量字符串&
,这样它仍然可以处理左值和右值,但是您必须实现它,就像操作符+=
实现一样,以避免在连接到它之前复制lhs
的额外分配:
friend String operator+(const String &lhs, const String &rhs)
{
/*
String tmp(lhs);
tmp += rhs;
return tmp;
*/
String tmp;
tmp.m_length = lhs.m_length + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs.m_data, lhs.m_length, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + lhs.m_length);
tmp.m_data[tmp.m_length] = 0;
return tmp;
}
无论哪种方式,您还应该为const char*
输入定义转换构造函数和operator+
:
class String
{
public:
...
String(const char *src);
...
friend String operator+(const char *lhs, const String &rhs)
{
return String(lhs) + rhs;
/* or:
std::size_t len = std::strlen(lhs);
String tmp;
tmp.m_length = len + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs, len, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + len);
tmp.m_data[tmp.m_length] = 0;
return tmp;
*/
}
...
};
这将允许将String
对象与字符串文本(String+“literal”
,“literal”+String
,String+=“literal”
等)连接起来
有关更多详细信息,请参见上。首先,确保在字符串类中定义复制和移动构造函数:
class String
{
private:
char *m_data;
std::size_t m_length;
...
public:
String();
String(const String &src);
String(String &&src);
~String();
...
};
然后为类定义operator+
和operator+=
:
class String
{
public:
...
String& operator+=(const String &rhs);
...
friend String operator+(String lhs, const String &rhs)
{
lhs += rhs;
return lhs;
}
};
通过将常量字符串&
作为右侧的输入,它将处理左值和右值输入
对于操作符+
,左边是值,因此编译器可以根据输入是左值(复制)还是右值(移动)来决定要使用的最佳构造函数
或者,您可以将其实现为在左侧使用常量字符串&
,这样它仍然可以处理左值和右值,但是您必须实现它,就像操作符+=
实现一样,以避免在连接到它之前复制lhs
的额外分配:
friend String operator+(const String &lhs, const String &rhs)
{
/*
String tmp(lhs);
tmp += rhs;
return tmp;
*/
String tmp;
tmp.m_length = lhs.m_length + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs.m_data, lhs.m_length, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + lhs.m_length);
tmp.m_data[tmp.m_length] = 0;
return tmp;
}
无论哪种方式,您还应该为const char*
输入定义转换构造函数和operator+
:
class String
{
public:
...
String(const char *src);
...
friend String operator+(const char *lhs, const String &rhs)
{
return String(lhs) + rhs;
/* or:
std::size_t len = std::strlen(lhs);
String tmp;
tmp.m_length = len + rhs.m_length;
tmp.m_data = new char[tmp.m_length+1];
std:copy_n(lhs, len, tmp.m_data);
std:copy_n(rhs.m_data, rhs.m_length, tmp.m_data + len);
tmp.m_data[tmp.m_length] = 0;
return tmp;
*/
}
...
};
这将允许将String
对象与字符串文本(String+“literal”
,“literal”+String
,String+=“literal”
等)连接起来
有关详细信息,请参见上。我通常这样做:
class foo
{
...
public:
...
foo&& operator +(foo const & other) &&;
foo&& operator +(foo && other) const &;
foo&& operator +(foo && other) &&;
foo operator +(foo const & other) const &;
};
不确定Microsoft是否支持这一点,但在较新的标准中,这是一种很好的方法。如果msvc不允许,试试叮当声
这样做的好处是,您可以对所使用的方法进行非常精细的控制。如果需要,还可以在类外定义这4个操作。但对于r值/l值组合的4种可能性,您总是需要4
此外,您通常希望将l值限定为常量,以指示它们未被修改
简单地定义复制/移动构造函数通常不是解决此问题的有效方法。您需要很好地了解右值引用如何有效地实现此功能。我通常这样做:
class foo
{
...
public:
...
foo&& operator +(foo const & other) &&;
foo&& operator +(foo && other) const &;
foo&& operator +(foo && other) &&;
foo operator +(foo const & other) const &;
};
不确定Microsoft是否支持这一点,但在较新的标准中,这是一种很好的方法。如果msvc不允许,试试叮当声
这样做的好处是,您可以对所使用的方法进行非常精细的控制。如果需要,还可以在类外定义这4个操作。但对于r值/l值组合的4种可能性,您总是需要4
此外,您通常希望将l值限定为常量,以指示它们未被修改
简单地定义复制/移动构造函数通常不是解决此问题的有效方法。您需要很好地理解右值引用如何有效地实现这一点。您肯定缺少标准重载const-String&,const-String&
。您可以找到一些指导和示例。数百万人在编写自己的字符串类之前,从未制作过比标准字符串类功能更好或bug更少的字符串类。所以,除非这只是一个学术练习,否则就放弃这个目标吧@ChristopherPisz如果std::string
的作者有这样一个attidute,那么我们就只有最糟糕的实现了。看到右值的好处是你知道它是一个临时值,并且可以自由地将它搞砸(确保析构函数仍然工作)。例如,在第三个重载中,可以执行lhs+=rhs;返回标准::移动(lhs)
从lhs
窃取资源,避免你自己的资源,但既然lhs
马上就死了,那没关系。@Rostislavstoyanov好吧,这是一个学术背景。我同情你。不使用STL的地方创建我必须使用的不使用STL的程序员:/您肯定缺少标准重载const-String&,const-String&
。您可以找到一些指导和示例。数百万人在编写自己的字符串类之前,从未制作过比标准字符串类功能更好或bug更少的字符串类。所以,除非这只是一个学术练习,否则就放弃这个目标吧@ChristopherPisz如果std::string
的作者有这样一个attidute,那么我们就只有最糟糕的实现了。看到右值的好处是你知道它是一个临时值,并且可以自由地将它搞砸(确保析构函数仍然工作)。例如,在第三个重载中,可以执行lhs+=rhs;返回标准::移动(lhs)代码>从中窃取资源