ReadingLab / Discussion-for-Cpp

C++ 中文讨论区
MIT License
89 stars 63 forks source link

StrVec和Vec的实现 #58

Open Nwpuer opened 8 years ago

Nwpuer commented 8 years ago

ex13.39(实现StrVec)中的alloc为什么不像书上那样声明为static成员呢? 我在实现ex16.16(将StrVec实现为模板)时,发现将alloc声明为非static成员会编译通过,而如果将它声明为static的话,VS2013会提示“无法解析的外部符号”,能不能解释一下为什么?

pezy commented 8 years ago

ex13.39(实现StrVec)中的alloc为什么不像书上那样声明为static成员呢?

13.5 章节里 StrVec 类的定义中,没把 alloc 声明为 static 啊。你指的是哪里的定义?

另外,为什么要声明为 static 呢?

我在实现ex16.16(将StrVec实现为模板)时,发现将alloc声明为非static成员会编译通过,而如果将它声明为static的话,VS2013会提示“无法解析的外部符号”,能不能解释一下为什么?

方便贴出代码吗?

Nwpuer commented 8 years ago

。。难道书不一样?我的是《C++ Primer》第五版中文版。在我的书上13.5章节中StrVec的定义中,关于alloc的定义是这样的:static std::allocator<std::string> alloc;而且应该不需要每个StrVec对象中都有一个alloc成员吧,将它定义成static从而与类直接相关比较好。 ex16.16是这样的: template <typename T> class Vec { ...... private: static std::allocator<T> alloc; ...... } 有static的话会提示“无法解析的外部符号”,去掉static的话会运行成功。会不会是VS2013不支持该特性?

sunmd01 commented 8 years ago

参考: http://tieba.baidu.com/p/4715599690

xialang2012 commented 7 years ago

http://blog.csdn.net/lwl_ls/article/details/3919028

ender233 commented 7 years ago

关于为什么static一定要类外定义,上面的链接解释的不错. 是否一定要做成static变量, 我针对这个问题讨论一下, 有不对的地方各位指正下.

c++表中中对内存的分配, 提供了std::allocator<T>, cppref上面查看内容就知道, 这个标准定义的内存分配类实际的内存分配和释放都是通过成员函数来实现的(allocatedeallocate), 只要想使用那必须得有个对象, 这也就是为什么LZ声明成static对象的原因, 因为这个对象又没状态啥的, 每一个类对象都存一个std::allocator岂不浪费?


那么,问题是一定要搞成static么? 未必 实际上如果不写容器类(并且自己搞定内存),std::allocator基本上也用不到, 我们来看一下SGI STL里面容器类是怎么定义的,以list为例,类的片段:

 template <class T, class Alloc = alloc>
 class list {
 protected:
     typedef void* void_pointer;
     typedef __list_node<T> list_node;
     typedef simple_alloc<list_node, Alloc> list_node_allocator;

 protected:
     link_type get_node() { return list_node_allocator::allocate(); }

得到几点结论:

没看过vs的STL咋实现的,是不是也提供了一个自己的内存分配类且提供了静态函数. 如果是,那么直接替换掉allocator的使用,可以规避掉非要声明个static对象了 如果不是, 自己实现一个内存分配类好了, SGI STL最终也不过是调用了malloc而已.

// alloc类内部实现, 提供了静态函数
 static void * allocate(size_t n)
 {
     void *result = malloc(n);
     if (0 == result) result = oom_malloc(n);
     return result;
 }

另外, c++11提供了allocator_traits, 提供了allocate的静态方法,可以调用,不过这个方法还是需要传递Alloc实例对象的,搞不清楚它存在的意义是啥.

// std::allocator_traits::allocate
static pointer allocate( Alloc& a, size_type n );
pezy commented 7 years ago

统一回复一下上面那几位:中文版有 static 是翻译者私自加上的,英文版没有。

@ender233

首先,SGI STL 的源码是 C++ 7的,非常非常古老。如果为了学习钻研,可以借鉴,但平心而论,其意义不大了。不如花时间去读 CppCoreGuidelines.

其次,你提到 VS, 而它恰恰就是用你后来提到的 allocator_traits实现。不仅 MS, 几乎所有现代编译器(G++, Clang) 都用这个来实现。

以下截自 Visual Studio 2017:

image

image

而 VS 有没有像你们猜测的那样,使用静态成员变量呢?其实并没有:

image

当然,这里的实现要比书上的例子复杂太多,所以情况不可一概而论。譬如这里的 _Compressed_pair 其实用到了将要进入标准的 range 库,未来容器的实现,恐怕都会像这个方向靠拢。

ender233 commented 7 years ago

really make sense!

首先,SGI STL 的源码是 C++ 7的,非常非常古老。如果为了学习钻研,可以借鉴,但平心而论,其意义不大了

习惯了套路还是能看懂的,其他版本我看的有点晕. SGI早起的版本继承比较少,新的SGI各种继承也复杂。SGI还是可以入门看看的。