最大长度的字符串类型
String type with max length
我需要实现一个 C++11 或 C++14 类型的字符串,它的行为就像 std:string
,但有以下额外的 constraints/features:
- 声明时指定的 WIDTH 参数。 STRING将
如果其长度大于 WIDTH
则抛出异常
- 声明期间指定的可选 FIXED 参数。如果 STRING 的长度不等于 WIDTH
,将抛出异常
在所有其他方面,STRING 应该表现得像 std::string
并公开与 std:string
相同的成员函数(例如 .append()
等)。
我的第一直觉是使用包含 std::string
的模板 class STRING
,如下所示:
template<int WIDTH= 0, bool FIXED = false>
class STRING {
static_assert(WIDTH >= 0, "WIDTH of STRING cannot be negative.");
public:
STRING() : value{} { }
STRING(const std::string &s) { if (is_valid(s)) value = s; }
STRING(const char c[]) { if (is_valid(c)) value = c; }
STRING& operator=(const std::string& s){ if (is_valid(s)) value = s;}
operator std::string() const { return value; }
std::string value;
private:
bool is_valid(const std::string &s) {
if (WIDTH && s.length() > WIDTH)
throw std::length_error{"STRING assignment failed. STRING too long."};
if (FIXED && s.length() != WIDTH)
throw std::length_error{"STRING assignment failed. STRING has wrong length."};
return true;
}
};
但是,上面的 STRING
模板 class 没有公开 std::string
成员函数,我不想重新实现整个 std::basic_char
函数集,所以我认为我的方法从根本上是错误的。我怀疑以某种方式扩展 std::string
可能会更好,但使用标准库类型 "mess" 似乎有点可怕。
我不确定这里的最佳方法是什么,非常欢迎指向正确方向的指示。
完成此操作的最简单方法是修改分配器模板参数。请注意 std::string
是
的 shorthand
std::basic_string<char, std::char_traits<char>, std::allocator<char>>
在分配器中,您可以放置检查溢出或长度的功能。
查看 this Q&A on advice on how to write a custom allocator. Howard Hinnant's website 中的示例,了解如何限制您需要复制的样板文件。
正如@rici 所说,大多数实现将使用 short-string-optimization (SSO)。这意味着字符串 class 将有一个 union
的小 stack-based 存储空间(通常为 24 字节左右)和三个指向堆的指针。这意味着对于小字符串,提供的分配器可能会被完全忽略。这实际上意味着您不能将字符串限制为非常小(低于 SSO 阈值)。
我需要实现一个 C++11 或 C++14 类型的字符串,它的行为就像 std:string
,但有以下额外的 constraints/features:
- 声明时指定的 WIDTH 参数。 STRING将 如果其长度大于 WIDTH 则抛出异常
- 声明期间指定的可选 FIXED 参数。如果 STRING 的长度不等于 WIDTH ,将抛出异常
在所有其他方面,STRING 应该表现得像 std::string
并公开与 std:string
相同的成员函数(例如 .append()
等)。
我的第一直觉是使用包含 std::string
的模板 class STRING
,如下所示:
template<int WIDTH= 0, bool FIXED = false>
class STRING {
static_assert(WIDTH >= 0, "WIDTH of STRING cannot be negative.");
public:
STRING() : value{} { }
STRING(const std::string &s) { if (is_valid(s)) value = s; }
STRING(const char c[]) { if (is_valid(c)) value = c; }
STRING& operator=(const std::string& s){ if (is_valid(s)) value = s;}
operator std::string() const { return value; }
std::string value;
private:
bool is_valid(const std::string &s) {
if (WIDTH && s.length() > WIDTH)
throw std::length_error{"STRING assignment failed. STRING too long."};
if (FIXED && s.length() != WIDTH)
throw std::length_error{"STRING assignment failed. STRING has wrong length."};
return true;
}
};
但是,上面的 STRING
模板 class 没有公开 std::string
成员函数,我不想重新实现整个 std::basic_char
函数集,所以我认为我的方法从根本上是错误的。我怀疑以某种方式扩展 std::string
可能会更好,但使用标准库类型 "mess" 似乎有点可怕。
我不确定这里的最佳方法是什么,非常欢迎指向正确方向的指示。
完成此操作的最简单方法是修改分配器模板参数。请注意 std::string
是
std::basic_string<char, std::char_traits<char>, std::allocator<char>>
在分配器中,您可以放置检查溢出或长度的功能。
查看 this Q&A on advice on how to write a custom allocator. Howard Hinnant's website 中的示例,了解如何限制您需要复制的样板文件。
正如@rici 所说,大多数实现将使用 short-string-optimization (SSO)。这意味着字符串 class 将有一个 union
的小 stack-based 存储空间(通常为 24 字节左右)和三个指向堆的指针。这意味着对于小字符串,提供的分配器可能会被完全忽略。这实际上意味着您不能将字符串限制为非常小(低于 SSO 阈值)。