c – 接口设计:采用字符串和字符串数组的重载函数的安全性

前端之家收集整理的这篇文章主要介绍了c – 接口设计:采用字符串和字符串数组的重载函数的安全性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
假设我们有一个可以将东西写入输出的类
  1. class Writer
  2. {
  3. public:
  4. int write(const std::string& str);
  5. int write(const char* str,int len);
  6. //...
  7. };

我很好,这很灵活,所有这一切,直到我意识到

  1. char* buf = new char[n]; //not terminated with '\0'
  2. //load up buf
  3. Writer w;
  4. w.write(buf); //compiles!

这是一个非常讨厌的bug.

我们可以用一些模板来修改

  1. class WriterV2
  2. {
  3. public:
  4. int write(const std::string& str);
  5. int write(const char* str,int len);
  6. template<typename... Args>
  7. int write(const char*,Args...)
  8. { static_assert(sizeof...(Args) < 0,"Incorrect arguments"); }
  9. //...
  10. };

但这种方法存在问题

  1. WriterV2 w;
  2. w.write("The templating genius!"); //compile error

我该怎么办?什么是更好的设计?

在有人要求之前,重载为const char(&)[N] does not work.创建一个包装器来实现这一点可能是可行的,但这看起来……有点过分了吗?

编辑添加方法write(char *)并发出错误并不理想.当通过函数和所有这些传递buf时,它可能变成const char *.

解决方法

在C中的重载分辨率期间 ICS (Implicit Conversion Sequences)可以产生令人惊讶的结果,你已经注意到了,也很烦人..

您可以提供所需的必要接口,然后通过利用partial ordering删除不需要的重载,仔细使用模板来处理字符串文字与const char * fiasco.

码:

  1. #include <iostream>
  2. #include <string>
  3. #include <type_traits>
  4.  
  5. class Writer
  6. {
  7. public:
  8. int write(std::string&&) { std::cout << "int write(std::string)\n"; return 0; }
  9. int write(const std::string&) { std::cout << "int write(const std::string& str)\n"; return 0; }
  10. int write(const char*,int){ std::cout << "int write(const char* str,int len)\n"; return 0; }
  11.  
  12. template<std::size_t N = 0,typename = std::enable_if_t<(N > 0)> >
  13. int write(const char (&)[N]) { std::cout << "int write(string-literal) " << N << " \n"; return 0; }
  14.  
  15.  
  16. template<typename T>
  17. int write(T&&) = delete;
  18.  
  19. };
  20.  
  21. int main(){
  22. char* buf = new char[30];
  23. const char* cbuf = buf;
  24. Writer w;
  25.  
  26. //w.write(buf); //Fails!
  27. //w.write(cbuf); //Fails!
  28. w.write(buf,30); //Ok! int write(const char*,int);
  29. w.write(std::string("Haha")); //Ok! int write(std::string&&);
  30. w.write("This is cool"); //Ok! int write(const char (&)[13]);
  31. }

打印:

  1. int write(const char* str,int len)
  2. int write(std::string)
  3. int write(string-literal) 13

Demo

请注意,上述解决方案继承了“使用无约束转发引用重载函数”的缺点.这意味着过载集中可行函数的参数类型的所有ICS都将被“删除

猜你在找的C&C++相关文章