Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StrVec和Vec的实现 #58

Open
Nwpuer opened this issue Mar 21, 2016 · 8 comments
Open

StrVec和Vec的实现 #58

Nwpuer opened this issue Mar 21, 2016 · 8 comments

Comments

@Nwpuer
Copy link

Nwpuer commented Mar 21, 2016

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

@pezy
Copy link
Member

pezy commented Mar 22, 2016

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

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

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

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

方便贴出代码吗?

@Nwpuer
Copy link
Author

Nwpuer commented Mar 22, 2016

。。难道书不一样?我的是《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
Copy link

sunmd01 commented Aug 7, 2016

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

@xialang2012
Copy link

@ender233
Copy link

ender233 commented Aug 20, 2017

关于为什么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(); }

得到几点结论:

  • SGI STL的实现中,默认的内存分配实现不是标准提供的std::allocator
  • 最终内存分配动作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
Copy link
Member

pezy commented Aug 23, 2017

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

@ender233

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

  • 这就解释了为什么它不用 std::allocator,因为那时候压根没这个。
  • 静态函数不等同于静态成员变量,前者会大量使用,而后者在现代C++实践中会尽量避免,因为其生命周期不可控。就以 StrVecalloc 为例,声明为 static 看似节省了空间,但破坏了对象的"粒度",这个成员成了一个"全局共享池",你甚至不清楚它会什么时候回收内存。其次,这一点点空间,压根没有必要节省,每个对象保证自己的 alloc 受自己控制,而不会和别的对象搅和到一起,这一点对于代码的清晰度来讲,是十分必要的。

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

以下截自 Visual Studio 2017:

image

image

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

image

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

@ender233
Copy link

really make sense!

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

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

@LakeishaKowalczyk
Copy link

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

应该版本问题,不是翻译者私加的,作者的示例源码 StrVec.h 中也是有 static 的
可能在不同的印刷批次中有过修改

private:
    static std::allocator<std::string> alloc; // allocates the elements

http://www.informit.com/title/032174113

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants