Raising exceptions in Rcpp - c++

I am trying to report errors from my rcpp code. I am using the constructor exception (const char *message_, const char *file, int line) from http://dirk.eddelbuettel.com/code/rcpp/html/classRcpp_1_1exception.html. To isolate the problem, I wrote the following bar.cpp:
#include <Rcpp.h>
RcppExport SEXP bar( SEXP x){
throw(Rcpp::exception("My Error Message","bar.cpp",4));
return x ;
}
When I run it in R, this is what I get:
> dyn.load("bar.so")
> is.loaded("bar")
[1] TRUE
> .Call("bar",12)
Error: SET_VECTOR_ELT() can only be applied to a 'list', not a 'NULL'
>

You can either
use the inline package which puts a try/catch block into the function it generates for you (by using two simple macros)
or do it manually yourself as shown in a bunch of examples on my blog, or in the examples/ section of the Rcpp package,
but doing what you (ie: throwing outside of a try/catch block) can never work.
As an added bonus, here is a complete example (which essentially already existed in the unit tests):
R> library(inline)
R> f <- cxxfunction(signature(), plugin="Rcpp", body='
+ throw std::range_error("boom");
+ return R_NilValue;
+ ')
R> f()
Error in f() : boom
R>
Again, cxxfunction() puts a try/catch() block in here for you as you can see if you turn verbose on:
R> f <- cxxfunction(signature(), plugin="Rcpp", body='
+ throw std::range_error("boom");
+ return R_NilValue;
+ ', verbose=TRUE)
>> setting environment variables:
PKG_LIBS = -L/usr/local/lib/R/site-library/Rcpp/lib \
-lRcpp -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib
>> LinkingTo : Rcpp
CLINK_CPPFLAGS = -I"/usr/local/lib/R/site-library/Rcpp/include"
>> Program source :
1 :
2 : // includes from the plugin
3 :
4 : #include <Rcpp.h>
5 :
6 :
7 : #ifndef BEGIN_RCPP
8 : #define BEGIN_RCPP
9 : #endif
10 :
11 : #ifndef END_RCPP
12 : #define END_RCPP
13 : #endif
14 :
15 : using namespace Rcpp;
16 :
17 :
18 :
19 : // user includes
20 :
21 :
22 : // declarations
23 : extern "C" {
24 : SEXP file4cc53282( ) ;
25 : }
26 :
27 : // definition
28 :
29 : SEXP file4cc53282( ){
30 : BEGIN_RCPP
31 :
32 : throw std::range_error("boom");
33 : return R_NilValue;
34 :
35 : END_RCPP
36 : }
37 :
38 :
Compilation argument:
/usr/lib/R/bin/R CMD SHLIB file4cc53282.cpp 2> file4cc53282.cpp.err.txt
ccache g++-4.6 -I/usr/share/R/include \
-I"/usr/local/lib/R/site-library/Rcpp/include" \
-fpic -g0 -O3 -Wall -pipe -Wno-unused -pedantic -c file4cc53282.cpp \
-o file4cc53282.o
g++ -shared -o file4cc53282.so file4cc53282.o \
-L/usr/local/lib/R/site-library/Rcpp/lib \
-lRcpp -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib \
-L/usr/lib/R/lib -lR
R>
The BEGIN_RCPP and END_CPP add the magic you need here.
Please do move your questions to rcpp-devel.

Just wrap your code inside BEGIN_RCPP/END_RCPP:
RcppExport SEXP bar( SEXP x){
BEGIN_RCPP
throw(Rcpp::exception("My Error Message","bar.cpp",4));
return x ;
END_RCPP
}
Note that you can throw normal std exceptions too:
throw std::invalid_argument("'x' is too short");

Related

boost::exists for symlinks do not dereference

In boost::filesystem, the path class always tries to dereference symlinks. A lot of the API is catered towards trying to make symlinks seem invisible. I'm guessing a lot of their syscalls underneath are stat related instead of lstat related. This is problematic for me, as I'm trying to get the symlink itself.
For example, doing fs::exists("some_symlink") because, although some_symlink exists, its referent does not exist. I want this to give me back true, and in the older versions of boost it supports it: https://www.boost.org/doc/libs/1_32_0/libs/filesystem/doc/operations.htm#symbolic_link_exists
However, now it doesnt. Is there any good way of doing this?
You can use boost::filesystem::symlink_status to get a file_status, and then check its type().
#include <boost/filesystem.hpp>
#include <iostream>
#include <iomanip>
int main(){
auto a = boost::filesystem::symlink_status("a_symlink");
auto b = boost::filesystem::symlink_status("main.cpp");
auto c = boost::filesystem::symlink_status("not_existing");
auto d = boost::filesystem::symlink_status("a_broken_symlink");
std::cout << std::boolalpha
<< (a.type() == boost::filesystem::file_not_found) << " "
<< (b.type() == boost::filesystem::file_not_found) << " "
<< (c.type() == boost::filesystem::file_not_found) << " "
<< (d.type() == boost::filesystem::file_not_found) << "\n";
}
Execution:
$ touch f
$ ln -s main.cpp a_symlink
$ ln -s f a_broken_symlink
$ rm f
$ ls -l
total 4
lrwxrwxrwx 1 2001 2000 1 Jun 3 23:33 a_broken_symlink -> f
lrwxrwxrwx 1 2001 2000 8 Jun 3 23:33 a_symlink -> main.cpp
-rw-rw-rw- 1 2001 2000 637 Jun 3 23:33 main.cpp
$ g++ -std=c++14 -Wall -Wextra -pedantic -lboost_filesystem -lboost_system main.cpp && ./a.out
false false true false
Live on Coliru

How to write binary operator with two post operands syntax with Boost Spirit x3?

I am following this example: https://github.com/boostorg/spirit/blob/develop/example/x3/calc/calc9/expression_def.hpp
What I am trying to accomplish is to write a rule that parses and generates like min{x}{y}. Mostly the code is using expression grammar like x + y, but now I want to place and parse both operands to the rhs of the operator.
I added the following code in expression_def.hpp file:
...
x3::symbols<ast::optoken> additive_op;
x3::symbols<ast::optoken> multiplicative_op;
x3::symbols<ast::optoken> binarypost_op;
x3::symbols<ast::optoken> unary_op;
x3::symbols<> keywords;
...
binarypost_op.add
("min", ast::op_divide) // Dummy operation usage for now
;
...
struct binarypost_expr_class;
struct unary_expr_class;
...
typedef x3::rule<binarypost_expr_class, ast::expression>
binarypost_expr_type;
...
binarypost_expr_type const binarypost_expr = "binarypost_expr";
...
auto const multiplicative_expr_def =
binarypost_expr
>> *(multiplicative_op > binarypost_expr)
;
auto const binarypost_expr_def = // See the chaining operation
('{' > unary_expr > '}')
>> *(binarypost_op > ('{' > unary_expr > '}'))
;
auto const unary_expr_def =
primary_expr
| (unary_op > primary_expr)
;
This works fine. But it can only parse something like , {x} min {y}. I want to be able to parse min {x} {y}. I tried the many combinations such as :
binarypost_op >> ('{' > unary_expr > '}') > ('{' > unary_expr > '}') etc. But I cant seem to figure it out as to what is the right way to write this? Any suggestions / comments ?
Ok, here's the changes. The hard part is actually code-generating the builtin function.
Parsing
Step 1: extend AST
Always start with the AST. We want operands that can be function calls:
In ast.hpp:
struct function_call; // ADDED LINE
// ...
struct operand :
x3::variant<
nil
, unsigned int
, variable
, x3::forward_ast<unary>
, x3::forward_ast<expression>
, x3::forward_ast<function_call> // ADDED LINE
>
{
using base_type::base_type;
using base_type::operator=;
};
// ...
enum funtoken
{
fun_min,
fun_max,
};
// ...
struct function_call : x3::position_tagged
{
funtoken fun;
std::list<operand> args;
};
In ast_adapted.hpp:
BOOST_FUSION_ADAPT_STRUCT(client::ast::function_call,
fun, args
)
Step 2: extend grammar
(This is all in expression_def.hpp)
Let's be generic, so parse function name tokens using a symbol table:
x3::symbols<ast::funtoken> functions;
Which we have to initialize in add_keywords:
functions.add
("min", ast::fun_min)
("max", ast::fun_max)
;
Now declare a rule for function calls:
struct function_call_class;
typedef x3::rule<function_call_class, ast::function_call> function_call_type;
function_call_type const function_call = "function_call";
That's all red-tape. The "interesting thing" is the rule definition:
auto const function_call_def =
functions
>> '(' >> expression % ',' >> ')'
;
Well. That's underwhelming. Let's integrate into our primary expression rule:
auto const primary_expr_def =
uint_
| bool_
| function_call
| (!keywords >> identifier)
| ('(' > expression > ')')
;
Note the ordering. If you want to be able to add function names that collide with a keyword, you'll need to add precautions.
Also, lets make AST annotation work for our node:
struct function_call_class : x3::annotate_on_success {};
Code generation
It's easy to find where to add support for the new AST node:
In compiler.hpp:
bool operator()(ast::function_call const& x) const;
Now comes the hard part.
What's really required for general n-ary is an accumulator. Since we don't have registers, this would need to be a temporary (local). However, since the VM implementation doesn't have these, I've limited the implementation to a fixed binary function call only.
Note that the VM already has support for function calls. Functions can have locals. So, if you code-gen a variable-argument built-in function you can implement a left-fold recursive solution.
In compiler.cpp:
bool compiler::operator()(ast::function_call const& x) const
{
auto choice = [&](int opcode) {
BOOST_ASSERT(x.args.size() == 2); // TODO FIXME hardcoded binary builtin
auto it = x.args.begin();
auto& a = *it++;
if (!boost::apply_visitor(*this, a))
return false;
auto& b = *it++;
if (!boost::apply_visitor(*this, b))
return false;
program.op(opcode); // the binary fold operation
program.op(op_jump_if, 0);
size_t const branch = program.size()-1;
if (!boost::apply_visitor(*this, a))
return false;
program.op(op_jump, 0);
std::size_t continue_ = program.size()-1;
program[branch] = int(program.size()-branch);
if (!boost::apply_visitor(*this, b))
return false;
program[continue_] = int(program.size()-continue_);
return true;
};
switch (x.fun) {
case ast::fun_min: return choice(op_lt);
case ast::fun_max: return choice(op_gt);
default: BOOST_ASSERT(0); return false;
}
return true;
}
I've just taken inspiration from the surrounding code on how to generate the jump labels.
Trying It Out
A simplistic example would be: var x = min(1,3);
Assembler----------------
local x, #0
start:
op_stk_adj 1
op_int 1
op_int 3
op_lt
op_jump_if 13
op_int 1
op_jump 15
13:
op_int 3
15:
op_store x
end:
-------------------------
Results------------------
x: 1
-------------------------
Running it with some random contrived input:
./test <<< "var a=$(($RANDOM % 100)); var
b=$(($RANDOM % 100)); var contrived=min(max(27,2*a), 100+b);"
Prints e.g.:
Assembler----------------
local a, #0
local b, #1
local contrived, #2
start:
op_stk_adj 3
op_int 31
op_store a
op_int 71
op_store b
op_int 27
op_int 2
op_load a
op_mul
op_gt
op_jump_if 24
op_int 27
op_jump 29
24:
op_int 2
op_load a
op_mul
29:
op_int 100
op_load b
op_add
op_lt
op_jump_if 58
op_int 27
op_int 2
op_load a
op_mul
op_gt
op_jump_if 51
op_int 27
op_jump 56
51:
op_int 2
op_load a
op_mul
56:
op_jump 63
58:
op_int 100
op_load b
op_add
63:
op_store contrived
end:
-------------------------
Results------------------
a: 31
b: 71
contrived: 62
-------------------------

tree.hh doesn't compile on Ubuntu 14.04

I am using the latest tree.hh from http://tree.phi-sci.com/download.html.
It produces the errors (please see below). How can I fix it? How can this class produce so many errors?
Thanks in advance for your suggesstions?
In file included from item_tree.h:4:0,
from Player.h:44,
from xinemediaplayer.c:26:
tree.hh:82:36: error: expected ‘,’ or ‘...’ before ‘&&’ token
tree(tree<T, tree_node_allocator>&&); // move constructor^M
^
tree.hh:82:38: error: invalid constructor; you probably meant ‘tree<T, tree_node_allocator> (const tree<T, tree_node_allocator>&)’
tree(tree<T, tree_node_allocator>&&); // move constructor^M
^
tree.hh:85:70: error: expected ‘,’ or ‘...’ before ‘&&’ token
tree<T,tree_node_allocator>& operator=(tree<T, tree_node_allocator>&&); // move assignment^M
^
tree.hh:503:64: error: expected ‘,’ or ‘...’ before ‘&&’ token
tree<T, tree_node_allocator>::tree(tree<T, tree_node_allocator>&& x) ^M
^
tree.hh:503:1: error: prototype for ‘tree<T, tree_node_allocator>::tree(tree<T, tree_node_allocator>)’ does not match any in class ‘tree<T, tree_node_allocator>’
tree<T, tree_node_allocator>::tree(tree<T, tree_node_allocator>&& x) ^M
^
tree.hh:81:3: error: candidates are: tree<T, tree_node_allocator>::tree(const tree<T, tree_node_allocator>&)
tree(const tree<T, tree_node_allocator>&); // copy constructor^M
^
tree.hh:80:3: error: tree<T, tree_node_allocator>::tree(const tree<T, tree_node_allocator>::iterator_base&)
tree(const iterator_base&);^M
^
tree.hh:496:1: error: tree<T, tree_node_allocator>::tree(const T&)
tree<T, tree_node_allocator>::tree(const T& x) ^M
^
tree.hh:490:1: error: tree<T, tree_node_allocator>::tree()
tree<T, tree_node_allocator>::tree() ^M
^
tree.hh:562:98: error: expected ‘,’ or ‘...’ before ‘&&’ token
tree<T,tree_node_allocator>& tree<T, tree_node_allocator>::operator=(tree<T, tree_node_allocator>&& x)^M
^
tree.hh: In member function ‘tree<T, tree_node_allocator>& tree<T, tree_node_allocator>::operator=(tree<T, tree_node_allocator>)’:...
an example of tree.hh:
64 template <class T, class tree_node_allocator = std::allocator<tree_node_<T> > >
65 class tree {
66 protected:
67 typedef tree_node_<T> tree_node;
68 public:
69 /// Value of the data stored at a node.
70 typedef T value_type;
71
72 class iterator_base;
73 class pre_order_iterator;
74 class post_order_iterator;
75 class sibling_iterator;
76 class leaf_iterator;
77
78 tree(); // empty constructor
79 tree(const T&); // constructor setting given element as head
80 tree(const iterator_base&);
81 tree(const tree<T, tree_node_allocator>&); // copy constructor
82 tree(tree<T, tree_node_allocator>&&); // move constructor
83 ~tree();
84 tree<T,tree_node_allocator>& operator=(const tree<T, tree_node_allocator>&); // copy assignment
85 tree<T,tree_node_allocator>& operator=(tree<T, tree_node_allocator>&&); // move assignment
86
87 /// Base class for iterators, only pointers stored, no traversal logic.
88 #ifdef __SGI_STL_PORT
89 class iterator_base : public stlport::bidirectional_iterator<T, ptrdiff_t> {
90 #else
The Makefile is:
1 PLUGIN = xinemediaplayer
2 OBJS = $(PLUGIN).o Control.o Player.o Reel.o SpuDecode.o Utils.o \
3 curl_download.o imagetools.o \
4 item_tree.o m3u_parser.o pls_parser.o timecounter.o \
5 xineOsd.o xineOsdInfoMenu.o xineOsdFunction.o Playlist.o
6 VDRDIR = ../../..
7 LIBDIR = ../../lib
8 TMPDIR = /tmp
9 -include $(VDRDIR)/Make.config
10 ARCHIVE = $(PLUGIN)-$(VERSION)
11 PACKAGE = vdr-$(ARCHIVE)
12 OBJS += cddb.o cdtext.o cdrom.o
13 OBJS += XineLib.o GstreamerLib.o gstTools.o ExternalLib.o
14 LIBS += -lxine `pkg-config --libs gstreamer-0.10` `pkg-config --libs gstreamer-interfaces-0.10`
15 INCLUDES += `pkg-config --cflags gstreamer-0.10` `pkg-config --cflags gstreamer-interfaces-0.10`
16 -include $(VDRDIR)/Make.common
17 INCLUDES +=
18 INCLUDES +=`taglib-config --cflags`
19 LDFLAGS +=`taglib-config --libs`
20 LIBS += `curl-config --libs` -lcdio -lcddb
21
22 DEFINES += -DPLAYER_VERSION=\"$(PLAYER_VERSION)\" -D__LINUX__ -D__STL_CONFIG_H
23
24 target-for-compatibility-with-vanilla-vdr:
25 $(LIBDIR)/$#.$(APIVERSION)
Make.config:
1 REELVDR=1
2 DEBUG = 1
3 VDRVER ?= 2.1
4 CCACHE := $(shell which ccache)
5 MAKE += -j3
6 LSB_RELEASE := $(shell lsb_release -sr)
7 MACHINE ?= -m32 -march=pentium3 -mmmx -msse -mfpmath=sse
8 CC = $(CCACHE) $(DISTCC) $(CROSS)gcc
9 CFLAGS = -O2 -g -pg $(MACHINE)
10 CXX = $(CCACHE) $(DISTCC) $(CROSS)g++
11 CXXFLAGS = -g3 -funroll-loops -fomit-frame-pointer $(MACHINE) -Wall -Woverloaded-virtual -D_FILE_OFFSET_BITS=64 -D_ LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
12 STRIP = $(CROSS)strip
13 export CC CXX CFLAGS CXXFLAGS
14 CC := $(CC)-4.8
15 CXX := $(CXX)-4.8
16 DEFINES += -DDVBAPI_V5
17 DEFINES += -DNEW_FFMPEG
18 USEMYSQL = 1
19 DEVICE_ATTRIBUTES = 1
20 DVBDIR := /usr/src/linux-headers-3.13.0-66-generic/include/config/dvb
21 VDRVER := 2.1
&& is C++ 11 feature.
You should use --std=c++11 or --std=gnu++11 command line option when making g++ call.

Boost Spirit: parse a section of an input

I have thousands of lines of input, that each line consists of 3 ints and a comma at the and that look like this:
5 6 10,
8 9 45,
.....
How can I create a grammar that parses only a certain section of an input, for example first 100 lines or from line 1000 to 1200 and ignores the rest.
My grammar currently looks like this:
qi::int_ >> qi::int_ >> qi::int_ >> qi::lit(",");
But obviously it parses the whole input.
You could just seek up to the interesting point and parse 100 lines there.
A sketch on how to skip 100 lines from just spirit:
Live On Coliru
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <tuple>
namespace qi = boost::spirit::qi;
int main() {
using It = boost::spirit::istream_iterator;
using Tup = std::tuple<int, int, int>;
It f(std::cin >> std::noskipws), l;
std::vector<Tup> data;
using namespace qi;
if (phrase_parse(f, l,
omit [ repeat(100) [ *(char_ - eol) >> eol ] ] >> // omit 100 lines
repeat(10) [ int_ >> int_ >> int_ >> ',' >> eol ], // parse 10 3-tuples
blank, data))
{
int line = 100;
for(auto tup : data)
std::cout << ++line << "\t" << boost::fusion::as_vector(tup) << "\n";
}
}
When tested with some random input like
od -Anone -t d2 /dev/urandom -w6 | sed 's/$/,/g' | head -200 | tee log | ./test
echo ============== VERIFY WITH sed:
nl log | sed -n '101,110p'
It'll print something expected, like:
101 (15400 5215 -20219)
102 (26426 -17361 -6618)
103 (-15311 -6387 -5902)
104 (22737 14339 16074)
105 (-28136 21003 -11594)
106 (-11020 -32377 -4866)
107 (-24024 10995 22766)
108 (3438 -19758 -10931)
109 (28839 22032 -7204)
110 (-25237 23224 26189)
============== VERIFY WITH sed:
101 15400 5215 -20219,
102 26426 -17361 -6618,
103 -15311 -6387 -5902,
104 22737 14339 16074,
105 -28136 21003 -11594,
106 -11020 -32377 -4866,
107 -24024 10995 22766,
108 3438 -19758 -10931,
109 28839 22032 -7204,
110 -25237 23224 26189,
Just because I want to learn more about Spirit X3, and because the worlds would like to know more about this upcoming version of the library, here's a more intricate version that shows a way to dynamically filter lines according to some expression.
In this case the lines are handled by this handler:
auto handle = [&](auto& ctx) mutable {
using boost::fusion::at_c;
if (++line_no % 10 == 0)
{
auto& attr = x3::_attr(ctx);
data.push_back({ at_c<0>(attr), at_c<1>(attr), at_c<2>(attr) });
}
};
As you'd expect every 10th line is included.
Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
int main() {
using It = boost::spirit::istream_iterator;
It f(std::cin >> std::noskipws), l;
struct Tup { int a, b, c; };
std::vector<Tup> data;
size_t line_no = 0;
auto handle = [&](auto& ctx) mutable {
using boost::fusion::at_c;
if (++line_no % 10 == 0)
{
auto& attr = x3::_attr(ctx);
data.push_back({ at_c<0>(attr), at_c<1>(attr), at_c<2>(attr) });
}
};
if (x3::phrase_parse(f, l, (x3::int_ >> x3::int_ >> x3::int_) [ handle ] % (',' >> x3::eol), x3::blank))
{
for(auto tup : data)
std::cout << tup.a << " " << tup.b << " " << tup.c << "\n";
}
}
Prints e.g.
g++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp -o test
od -Anone -t d2 /dev/urandom -w6 | sed 's/$/,/g' | head -200 | tee log | ./test
echo ============== VERIFY WITH perl:
nl log | perl -ne 'print if $. % 10 == 0'
-8834 -947 -8151
13789 -20056 -11874
6919 -27211 -19472
-7644 18021 13523
-20120 16923 -11419
27772 31149 14005
3540 4894 -24790
10698 10223 -30397
-22533 -32437 -13665
25813 3264 -16414
11453 11955 18268
5092 27052 17930
10915 6493 20432
-14380 -6085 -25430
18599 6710 17279
22049 22259 -32189
1048 14621 6452
-24996 10856 29429
3537 -26338 19623
-4117 6617 14009
============== VERIFY WITH perl:
10 -8834 -947 -8151,
20 13789 -20056 -11874,
30 6919 -27211 -19472,
40 -7644 18021 13523,
50 -20120 16923 -11419,
60 27772 31149 14005,
70 3540 4894 -24790,
80 10698 10223 -30397,
90 -22533 -32437 -13665,
100 25813 3264 -16414,
110 11453 11955 18268,
120 5092 27052 17930,
130 10915 6493 20432,
140 -14380 -6085 -25430,
150 18599 6710 17279,
160 22049 22259 -32189,
170 1048 14621 6452,
180 -24996 10856 29429,
190 3537 -26338 19623,
200 -4117 6617 14009,

How much memory consumed by my object

I want to know programmatic way to get the memory consumed by my user defined class.
Following is the declaration of the class
struct TrieNode {
typedef std::map<char, TrieNode *> ChildType;
std::string m_word;
bool m_visited;
}
I have inserted around 264061 words into this Trie. After this when i do sizeof(trieobject) it just show me 32. How do i know how much exact memory is used by such data structures.
I use
valgrind --tool=massif ./myprogram -opt arg1 arg2
ms_print massif.* | less -SR
for that. Sample output from this page
19.63^ ###
| #
| # ::
| # : :::
| :::::::::# : : ::
| : # : : : ::
| : # : : : : :::
| : # : : : : : ::
| ::::::::::: # : : : : : : :::
| : : # : : : : : : : ::
| ::::: : # : : : : : : : : ::
| ###: : : # : : : : : : : : : #
| ::# : : : # : : : : : : : : : #
| :::: # : : : # : : : : : : : : : #
| ::: : # : : : # : : : : : : : : : #
| ::: : : # : : : # : : : : : : : : : #
| :::: : : : # : : : # : : : : : : : : : #
| ::: : : : : # : : : # : : : : : : : : : #
| :::: : : : : : # : : : # : : : : : : : : : #
| ::: : : : : : : # : : : # : : : : : : : : : #
0 +----------------------------------------------------------------------->KB 0 29.48
Number of snapshots: 25
Detailed snapshots: [9, 14 (peak), 24]
The remainder of the log details the highest percentiles of memory allocations, you can specifically see what type of class takes what % of heap memory (and where the allocations originate in terms of call stack), e.g.:
--------------------------------------------------------------------------------
n time(B) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
10 10,080 10,080 10,000 80 0
11 12,088 12,088 12,000 88 0
12 16,096 16,096 16,000 96 0
13 20,104 20,104 20,000 104 0
14 20,104 20,104 20,000 104 0
99.48% (20,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->49.74% (10,000B) 0x804841A: main (example.c:20)
|
->39.79% (8,000B) 0x80483C2: g (example.c:5)
| ->19.90% (4,000B) 0x80483E2: f (example.c:11)
| | ->19.90% (4,000B) 0x8048431: main (example.c:23)
| |
| ->19.90% (4,000B) 0x8048436: main (example.c:25)
|
->09.95% (2,000B) 0x80483DA: f (example.c:10)
->09.95% (2,000B) 0x8048431: main (example.c:23)
Well, this is not so easy to do. First of all m_word is a string with variable size right? Internally the std::string holds an array of chars among other things. The same stands for std::map. I guess you could get a rough estimation based on the size of the map * TrieNode but this will be just a rough estimate.
I think some code profiling with an external tool would be of more help. Hell you can even use the task manager if you are out of any tools left :).
Your "object size" is sizeof(std::string) + sizeof(bool) + m_word.capacity() + padding bytes or sizeof(trieobject) + m_word.capacity()
Here's a piece of code for GCC that I came up with that you can use in a test program where you only instantiate one object of your class and do some typical work with it. The code replaces the global operator new() and operator delete(); so it will only track allocations through ::new expressions and the standard allocator, provided that the standard allocator itself uses ::operator new() (this is the case for GCC).
Since we need to track the pointers and their allocations, we need a separate map for that, which of course cannot use the standard allocator itself; GCC's malloc-allocator comes to the rescue.
We use a statically initialized global to make the memory tracker print its data after main returns.
#include <unordered_map>
#include <string>
#include <iostream>
#include <ext/malloc_allocator.h>
struct Memtrack
{
typedef std::unordered_map<void*, std::size_t, std::hash<void*>,
std::equal_to<void*>, __gnu_cxx::malloc_allocator<void*>> AllocMap;
static int memtrack;
static int memmax;
static AllocMap allocs;
Memtrack() { std::cout << "starting tracker: cur = " << memtrack << ", max = " << memmax << ".\n"; }
~Memtrack() { std::cout << "ending tracker: cur = " << memtrack << ", max = " << memmax << ".\n"; }
static void track_new(std::size_t n, void * p)
{
memtrack += n;
if (memmax < memtrack) memmax = memtrack;
allocs[p] = n;
std::cout << "... allocating " << n << " bytes...\n";
}
static void track_delete(void * p)
{
const int n = int(allocs[p]);
memtrack -= n;
std::cout << "... freeing " << n << " bytes...\n";
}
} m;
int Memtrack::memtrack = 0;
int Memtrack::memmax = 0;
Memtrack::AllocMap Memtrack::allocs;
void * operator new(std::size_t n) throw(std::bad_alloc)
{
void * const p = std::malloc(n);
Memtrack::track_new(n, p);
return p;
}
void operator delete(void * p) throw()
{
Memtrack::track_delete(p);
std::free(p);
}
int main()
{
std::cout << "Beginning of main.\n";
std::unordered_map<std::string, int> m; // this piece of code
m["hello"] = 4; // is a typical test for working
m["world"] = 7; // with dynamic allocations
std::cout << "End of main.\n";
}
Some typical output:
starting tracker: cur = 0, max = 0.
Beginning of main.
... allocating 48 bytes...
... allocating 12 bytes...
... allocating 12 bytes...
End of main.
... freeing 12 bytes...
... freeing 12 bytes...
... freeing 48 bytes...
ending tracker: cur = 0, max = 72.
Trivial. If you have some time (which might be the case, if you are only interested in the size for debugging/optimising purposes). This approach might be unsuited for production code!
#include <malloc.h>
template <typename T> int objSize(T const* obj) {
// instead of uordblks, you may be interested in 'arena', you decide!
int oldSize = mallinfo().uordblks;
T* dummy = new T(*obj);
int newSize = mallinfo().uordblks;
delete dummy;
return newSize - oldSize;
}