为什么/为什么不呢?
假设我有一个类,它在构造函数中包含一个字符串并存储它.这个类成员应该是一个指针,还是一个值?
class X { X(const std::string& s): s(s) {} const std::string s; };
要么...
class X { X(const std::string* s): s(s) {} const std::string* s; };
如果我存储原始类型,我会复制一份.如果我正在存储一个对象,我会使用一个指针.
我觉得我想复制那个字符串,但我不知道何时决定.我应该复制载体吗?集?地图?整个JSON文件......?
编辑:
听起来我需要阅读移动语义.但无论如何,我想让我的问题更具体一些:
如果我有一个10兆字节的文件作为常量字符串,我真的不想复制它.
如果我正在新建100个对象,将5个字符的const字符串传递给每个构造函数,那么它们都不应该拥有所有权.可能只是拿一个字符串的副本.
所以(假设我并非完全错误)很明显该从课外做什么,但是当你在设计时,你class GenericTextHaver
如何决定文本的方法呢?
如果你需要的是一个类,需要一个常量字符串在其构造,并让你获得一个常量字符串具有相同值了吧,你怎么决定如何在内部表示呢?
std :: string类成员应该是指针吗?
没有
那么为何不?
因为std :: string与标准库中的每个其他对象一样,并且c ++中的所有其他编写良好的对象都被设计为被视为值.
它可能会也可能不会在内部使用指针 - 这不是您的关注点.所有你需要知道的是,它的编写精美,行为非常有效(实际上比你现在可能想象的更有效)当被视为一个值...特别是如果你使用移动构造.
我觉得我想复制那个字符串,但我不知道何时决定.我应该复制载体吗?集?地图?整个JSON文件......?
是.一个编写良好的类具有"值语义"(这意味着它被设计为被视为一个值) - 因此被复制和移动.
曾几何时,当我第一次编写代码时,指针通常是使计算机快速执行某些操作的最有效方法.现在,通过内存缓存,管道和预取,复制几乎总是更快.(对真的!)
在多处理器环境中,除了最极端的情况外,复制速度要快得多.
如果我有一个10兆字节的文件作为常量字符串,我真的不想复制它.
如果您需要它的副本,请复制它.如果你真的只想移动它,那么std::move
它.
如果我正在新建100个对象,将5个字符的const字符串传递给每个构造函数,那么它们都不应该拥有所有权.可能只是拿一个字符串的副本.
一个5个字符的字符串复制起来很便宜,你甚至不应该考虑它.只需复制它.信不信由你,std::string
完全知道大多数字符串很短,而且经常被复制.这里甚至不会参与任何内存分配.
所以(假设我并非完全错误)很明显该从课外做什么,但是当你设计类GenericTextHaver时,你如何决定文本的方法呢?
以最优雅的方式表达代码,简洁地传达您的意图.让编译器决定机器代码的外观 - 这是它的工作.成千上万的人已经花时间确保它比以往更好地完成这项工作.
如果您只需要一个在其构造函数中包含const字符串的类,并允许您从中获取具有相同值的const字符串,那么您如何决定如何在内部表示它?
几乎在所有情况下,都要存储副本.如果2个实例实际上需要共享相同的字符串,那么考虑别的东西,比如a std::shared_ptr
.但在这种情况下,他们可能不仅需要共享一个字符串,所以'共享状态'应该封装在一些其他对象中(理想情况下是值语义!)
好的,别说了 - 告诉我课程应该怎么样
class X { public: // either like this - take a copy and move into place X(std::string s) : s(std::move(s)) {} // or like this - which gives a *miniscule* performance improvement in a // few corner cases /* X(const std::string& s) : s(s) {} // from a const ref X(std::string&& s) : s(std::move(s)) {} // from an r-value reference */ // ok - you made _s const, so this whole class is now not assignable const std::string s; // another way is to have a private member and a const accessor // you will then be able to assign an X to another X if you wish /* const std::string& value() const { return s; } private: std::string s; */ };
如果构造函数真正"接受一个字符串并存储它 ",那么你的类当然需要包含一个std::string
数据成员.指针只会指向你实际上并不拥有的其他字符串,更不用说"存储"了:
struct X { explicit X(std::string s) : s_(std::move(s)) {} std::string s_; };
请注意,既然我们取得了字符串的所有权,我们也可以按值获取它,然后从构造函数参数中移除.