如何创建采用 const char* "string literal" 的移动构造函数
how to create move constructor that takes const char* "string literal"
我想创建一个采用字符串文字的移动构造函数,然后将该 C 字符串移动到一个成员指针。
我能写的最好的解决方案是发出警告:
不赞成从字符串常量到 'char*' [-Wwrite-strings] 的转换
CTextBlock cctb("move(H)");
^
代码:
#include <iostream>
using namespace std;
class CTextBlock
{
public:
CTextBlock(char* &&text)//move constructor
{
pText = text;
}
private:
char *pText;
};
int main()
{
CTextBlock cctb("move(H)"); //WARNING
return 0;
}
字符串文字是 const char *
。无论它用作左值还是右值都是如此。
如果您再次检查您的代码,您将因此尝试将 const char *
存储到 char *
,这就是您的编译器诊断的来源。您的移动构造函数正在采用对 char *
而不是 const char *
的右值引用。将其更改为 const char *
,并将 pText
class 成员更改为 const char *
,您尝试执行的操作应该有效。
首先,字符串文字的类型是char const[N]
(适合常量N
)。该数组可以分配给 char const*
,在这种情况下,它将衰减为指向第一个元素的指针。它无法 转换为char*
。在 C++11 之前,允许转换到 char*
来处理现有代码,这些代码不是 const
-正确的(例如,因为它在 C 得到 const
之前作为 C 代码开始) .此转换已针对 C++11 移除。
问题是您实际尝试实现的目标:字符串文字是不可变的,并且在程序的整个生命周期内持续存在。您可以根据需要保留任意数量的指向它们的指针,移动指针毫无意义,因为它们的复制成本非常低。
在你的问题中,你指出你想要创建一个移动构造函数,但是移动构造函数采用了它们所针对的 class 的右值引用,例如,这将是你的移动构造函数 class:
CTextBlock::CTextBlock(CTextBlock&& other)
: pText(other.pText) {
other.pText = 0;
}
(您的 class 没有显示指针 pText
的任何所有权语义,在这种情况下,移动构造实际上没有多大意义;上面的代码假定存在一些所有权语义并且空指针表示该对象不拥有任何东西)。
仅仅因为参数被限制为右值引用并不意味着该函数是一个移动构造函数。它所暗示的是参数是一个右值,可以合理地假设它的当前表示不需要保留。字符串文字似乎是右值,因为字符串文字被转换为指向数组开头的 [临时] 指针。
一个相当接近于只允许文字的构造函数可以实现为一个模板:
#include <cstddef>
#include <assert>
struct X
{
char const * str;
std::size_t len;
template <std::size_t N>
X(char const (&a)[N]) : str(a), len(N - 1)
{
assert(a[len] == '[=10=]'); // true for string literals
}
};
虽然它不是万无一失的,因为它还会绑定到命名字符数组,并且如果您的字符串也包含空值,则长度计算是可疑的。但是,如果您试图避免意外使用动态值(例如,在从表达式和文字字符串构建字符串的算法中),这将非常有用。
我想创建一个采用字符串文字的移动构造函数,然后将该 C 字符串移动到一个成员指针。 我能写的最好的解决方案是发出警告: 不赞成从字符串常量到 'char*' [-Wwrite-strings] 的转换 CTextBlock cctb("move(H)"); ^ 代码:
#include <iostream>
using namespace std;
class CTextBlock
{
public:
CTextBlock(char* &&text)//move constructor
{
pText = text;
}
private:
char *pText;
};
int main()
{
CTextBlock cctb("move(H)"); //WARNING
return 0;
}
字符串文字是 const char *
。无论它用作左值还是右值都是如此。
如果您再次检查您的代码,您将因此尝试将 const char *
存储到 char *
,这就是您的编译器诊断的来源。您的移动构造函数正在采用对 char *
而不是 const char *
的右值引用。将其更改为 const char *
,并将 pText
class 成员更改为 const char *
,您尝试执行的操作应该有效。
首先,字符串文字的类型是char const[N]
(适合常量N
)。该数组可以分配给 char const*
,在这种情况下,它将衰减为指向第一个元素的指针。它无法 转换为char*
。在 C++11 之前,允许转换到 char*
来处理现有代码,这些代码不是 const
-正确的(例如,因为它在 C 得到 const
之前作为 C 代码开始) .此转换已针对 C++11 移除。
问题是您实际尝试实现的目标:字符串文字是不可变的,并且在程序的整个生命周期内持续存在。您可以根据需要保留任意数量的指向它们的指针,移动指针毫无意义,因为它们的复制成本非常低。
在你的问题中,你指出你想要创建一个移动构造函数,但是移动构造函数采用了它们所针对的 class 的右值引用,例如,这将是你的移动构造函数 class:
CTextBlock::CTextBlock(CTextBlock&& other)
: pText(other.pText) {
other.pText = 0;
}
(您的 class 没有显示指针 pText
的任何所有权语义,在这种情况下,移动构造实际上没有多大意义;上面的代码假定存在一些所有权语义并且空指针表示该对象不拥有任何东西)。
仅仅因为参数被限制为右值引用并不意味着该函数是一个移动构造函数。它所暗示的是参数是一个右值,可以合理地假设它的当前表示不需要保留。字符串文字似乎是右值,因为字符串文字被转换为指向数组开头的 [临时] 指针。
一个相当接近于只允许文字的构造函数可以实现为一个模板:
#include <cstddef>
#include <assert>
struct X
{
char const * str;
std::size_t len;
template <std::size_t N>
X(char const (&a)[N]) : str(a), len(N - 1)
{
assert(a[len] == '[=10=]'); // true for string literals
}
};
虽然它不是万无一失的,因为它还会绑定到命名字符数组,并且如果您的字符串也包含空值,则长度计算是可疑的。但是,如果您试图避免意外使用动态值(例如,在从表达式和文字字符串构建字符串的算法中),这将非常有用。