注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

c++之new操作符  

2013-10-07 23:03:15|  分类: C/C++基础 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、c++对于new操作符的定义
《ansi c++ reference》中5.3.4 New对于new相关操作符的说明
10 An implementation shall provide default definitions of the global allocation functions operator new() for nonarrays(3.7.3, 18.4.1.1) and operator new[]() for arrays (18.4.1.2). [Note: A C + + program can provide alternative definitions of these functions (17.3.3.4), and/or classspecific versions (12.5). ]
这里说明了对于new,每种编译器需要提供默认的operator new和operator new[]两种类型的实现,对于另一种我们常见的
new (placement) type类型并没有要求一定有定义和实现。看一下对于一个new操作符的使用例子
[root@Harry newplacement]# cat newplacement.cpp
int * foo()
{
    return new ((void*)0)int(-1);
}
[root@Harry newplacement]# gcc newplacement.cpp -c
newplacement.cpp: In function ‘int* foo()’:
newplacement.cpp:3: error: no matching function for call to ‘operator new(unsigned int, void*)’
<built-in>:0: note: candidates are: void* operator new(unsigned int)
[root@Harry newplacem
可以看到两个现象,一个是对于我们通常添加一个指定位置的函数调用,在没有包含头文件的情况下有编译错误,另一个现象就是编译器内置识别
void* operator new(unsigned int)
类型的操作符定义。
二、c++库对于void *偏移的定义
对于我们常见的void *偏移,这个在c++库中定义,而不是c++语言的内置操作符,区别就在于内置的不需要包含头文件就可以被编译器直接识别,而库函数的定义必须要包含头文件。
在gcc的c++库中,对于操作符的定义位于libstdc++-v3\libsupc++\new文件中
// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }
这个定义简单而猥琐,在看这个头文件的时候很容易被忽略掉,我也是使用工具搜索到的,在看这个文件的时候直接跳过了这个定义。对于加偏移量的new操作,默认的库函数只是简单的返回了用户提供的偏移地址,size参数并没有被使用到。
所以对于这个例子,我们添加一个对于new头文件的编译即可:
[root@Harry newplacement]# cat newplacement.cpp
#include <new>

int * foo()
{
    return new ((void*)0)int(-1);
}
[root@Harry newplacement]# gcc newplacement.cpp -c
[root@Harry newplacement]#
三、gcc对于new内置函数原型的初始化
这些分析都不专业,也不知道是怎么找到这里的,只是感觉应该是gcc的内部初始化方法:
gcc-4.1.0\gcc\cp\lex.c
cxx_init (void)

  /* We cannot just assign to input_filename because it has already
     been initialized and will be used later as an N_BINCL for stabs+
     debugging.  */
#ifdef USE_MAPPED_LOCATION
  push_srcloc (BUILTINS_LOCATION);
#else
  push_srcloc ("<built-in>", 0);
#endif
……
  init_operators ();
  init_method ();
  init_error ();

  current_function_decl = NULL;

  class_type_node = ridpointers[(int) RID_CLASS];

  cxx_init_decl_processing ();

static void
init_operators (void)
函数中,其中完成了对new的包含
#include "operators.def"
#undef DEF_OPERATOR
gcc-4.1.0\gcc\cp\operators.def
/* Memory allocation operators.  */
DEF_SIMPLE_OPERATOR ("new", NEW_EXPR, "nw", -1)
DEF_SIMPLE_OPERATOR ("new []", VEC_NEW_EXPR, "na", -1)
DEF_SIMPLE_OPERATOR ("delete", DELETE_EXPR, "dl", -1)
DEF_SIMPLE_OPERATOR ("delete []", VEC_DELETE_EXPR, "da", -1)
但是这里并没有说明操作符new的参数信息,这个参数及返回值在另外一个地方定义
cxx_init_decl_processing (void)
    tree newtype, deltype;
    tree ptr_ftype_sizetype;

    push_namespace (std_identifier);
    bad_alloc_id = get_identifier ("bad_alloc");
    bad_alloc_type_node = make_aggr_type (RECORD_TYPE);
    TYPE_CONTEXT (bad_alloc_type_node) = current_namespace;
    bad_alloc_decl
      = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node);
    DECL_CONTEXT (bad_alloc_decl) = current_namespace;
    TYPE_STUB_DECL (bad_alloc_type_node) = bad_alloc_decl;
    pop_namespace ();

    ptr_ftype_sizetype
      = build_function_type (ptr_type_node,
                 tree_cons (NULL_TREE,
                    size_type_node,
                    void_list_node));
构造函数类型,参数为单个size_type(void_list_node表示参数结束,不包含变参),返回值为void *类型的函数
    newtype = build_exception_variant
      (ptr_ftype_sizetype, add_exception_specifier
       (NULL_TREE, bad_alloc_type_node, -1));
    deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);new可能throw bad_alloc类型异常
    push_cp_library_fn (NEW_EXPR, newtype);
    push_cp_library_fn (VEC_NEW_EXPR, newtype);
相关变量及函数的说明
/* Construct, lay out and return
   the type of functions returning type VALUE_TYPE
   given arguments of types ARG_TYPES.
   ARG_TYPES is a chain of TREE_LIST nodes whose TREE_VALUEs
   are data type nodes for the arguments of the function.
   If such a type has already been constructed, reuse it.
  */

tree
build_function_type (tree value_type, tree arg_types)

/* The node that should be placed at the end of a parameter list to
   indicate that the function does not take a variable number of
   arguments.  The TREE_VALUE will be void_type_node and there will be
   no TREE_CHAIN.  Language-independent code should not assume
   anything else about this node
.  */
#define void_list_node                  global_trees[TI_VOID_LIST_NODE]

/* The C type `void *'.  */
#define ptr_type_node            global_trees[TI_PTR_TYPE]
对照一下c++库中对于new的声明
void* operator new(std::size_t) throw (std::bad_alloc);
void* operator new[](std::size_t) throw (std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();
四、C++标准对于new的说明
11 The newplacement
syntax can be used to supply additional arguments to an allocation function. If used, overloading resolution is done by assembling an argument list from the amount of space requested (the first argument) and the expressions in the newplacement part of the newexpression
(the second and succeeding arguments).
C++标准说明,placement中的列表将会把new需要的存储空间数量(作为第一个参数)和newplacement部分中的表达式列表(作为第二个和后继参数)作为调用参数来进行重载解析。所以,我们常见的单void *只是这种情况一个最为常见的特例应用,在有些情况下,这个new操作的placement可能会作为 filename linenumber两个参数来调用,然后用户重载这两个函数的调用,从而完成对于动态空间申请和释放的追踪。只是这种方法不能对于库函数中new操作完成hook,因为这个钩子是在编译是确定,所以最好应该是使用algrind之类的专业工具来进行动态内存的监控跟踪。
  评论这张
 
阅读(702)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017