v8js引擎常用C++代码片段

/***********************************************/
/** Embedder's Guide */
/** http://code.google.com/apis/v8/embed.html **/
/***********************************************/

/**
 * Constant
 **/
v8::True();
v8::False();
v8::Null();
v8::Undefined();

/**
 * Some classes
 **/
v8::Boolean
v8::Array
v8::Arguments
v8::Date
v8::Function
v8::Int32
v8::Integer
v8::Number
v8::Object
v8::Regexp
v8::Primitive
v8::Script
v8::String
v8::Uint32
v8::TryCatch
v8::V8

/**
 * Function signature
 **/
 static v8::Handle<v8::Value> FUNCTION(const v8::Arguments& args);

/**
 * Set simple property
 **/
process->Set(String::NewSymbol("platform"), String::New(PLATFORM));

/**
 * Return object
 **/
Handle<Object> NewObj(int x) { HandleScope handle_scope; Handle<Object> obj = Object::New(); obj->Set(String::NewSymbol("name"), Integer::New(x)); return handle_scope.Close(obj);}

/**
 * Return array
 **/
Handle<Array> NewPointArray(int x, int y, int z) { 
  // We will be creating temporary handles so we use a handle scope.
  HandleScope handle_scope; 
  // Create a new empty array.
  Handle<Array> array = Array::New(3); 
  //if can not determine the length of the array just left first parameter empty 
  Handle<Array> array = Array::New(); 
  // Return an empty result if there was an error creating the array.
  if (array.IsEmpty()) return Handle<Array>(); 
  // Fill out the values 
  array->Set(0, Integer::New(x));
  array->Set(1, Integer::New(y));
  array->Set(2, Integer::New(z)); 
  // Return the value through Close. 
  return array; 
  //ERROR 
  // The Close method copies the value of its argument into the enclosing scope
  // return handle_scope.Close(array);
}
/**
 * Accessor
 * accessor callbacks are invoked when a specific object property is accessed by a script
 **/
Handle<ObjectTemplate> global_templ = ObjectTemplate::New();
global_templ->SetAccessor(String::New("x"), XGetter, XSetter);
global_templ->SetAccessor(String::New("y"), YGetter, YSetter);
Handle<Value> XGetter(Local<String> property, const AccessorInfo& info) {
  return Integer::New(x);
}
void XSetter(Local<String> property, Local<Value> value, const AccessorInfo& info) {
  x = value->Int32Value();
}
/**
 * Interceptor * interceptor callbacks are invoked when any object property is accessed by a script * named property interceptors - called when accessing properties with string names. * ndexed property interceptors - called when accessing indexed properties.
 **/
Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
envTemplate->SetNamedPropertyHandler(EnvGetter, EnvSetter, EnvQuery, EnvDeleter, EnvEnumerator, Undefined());
Local<Object> env = envTemplate->NewInstance();process->Set(String::NewSymbol("env"), env); 

//Getter
static Handle<Value> EnvGetter(Local<String> property, const AccessorInfo& info) {
  String::Utf8Value key(property);
  const char* val = getenv(*key);
  if (val) { HandleScope scope;
    return scope.Close(String::New(val));
  }
  return Undefined(); 
} 

//Setter
static Handle<Value> EnvSetter(Local<String> property, Local<Value> value, const AccessorInfo& info) {
  String::Utf8Value key(property);
  String::Utf8Value val(value);
  #ifdef __POSIX__ setenv(*key, *val, 1);
  #else __WIN32__ NO_IMPL_MSG(setenv) return value;
} 

//Query
static Handle<Integer> EnvQuery(Local<String> property, const AccessorInfo& info) {
  String::Utf8Value key(property);
  if (getenv(*key)) {
    HandleScope scope;
    return scope.Close(Integer::New(None));
  }
  return Handle<Integer>();
}

//Deleter
static Handle<Boolean> EnvDeleter(Local<String> property, const AccessorInfo& info) {
  String::Utf8Value key(property);
  if (getenv(*key)) {
    #ifdef __POSIX__ unsetenv(*key);
    #else NO_IMPL_MSG(unsetenv)
    #endif
    return True();
  }
  return False();
} 

//Enumerator
static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
  HandleScope scope;
  int size = 0;
  while (environ[size]) size++;
  Local<Array> env = Array::New(size);
  for (int i = 0; i < size; ++i) {
    const char* var = environ[i];
    const char* s = strchr(var, '=');
    const int length = s ? s - var : strlen(var);
    env->Set(i, String::New(var, length));
  }
  return scope.Close(env);
}
/**
 * Create function object and set it's properties
 **/

/**
 * Exception
 **/
TryCatch trycatch;
Handle v = script->Run();
if (v.IsEmpty()) {
  Handle<value> exception = trycatch.Exception();
  String::AsciiValue exception_str(exception);
  printf("Exception: %s\n", *exception_str);
  // ...
}
if (args.Length() < 3 || !args[0]->IsString() || !args[1]->IsInt32() || !args[2]->IsInt32()) {
  return ThrowException( Exception::TypeError(String::New("Bad argument")));
}
/**
 * prototype
 **/
Handle<FunctionTemplate> biketemplate = FunctionTemplate::New();
biketemplate.PrototypeTemplate().Set( String::New("wheels"), FunctionTemplate::New(MyWheelsMethodCallback))

/**
 * Inheritance
 **/
void Inherit(Handle<FunctionTemplate> parent);biketmplate.Inherit(transportTemplate);

/**
 * Parameter conversion
 **/
 //int64 
int n = args[0]->IntegerValue(); return scope.Close(Number::New(n)); 
 //int32 
int n = args[0]->Int32Value(); 
//double
double d = args[0]->NumberValue(); 
//uint32
unsigned int ui = args[0]->Uint32Value(); 
//const
char* v8::String:Utf8Value str(args[0]); const char* cstr = *str ? *str : NULL;

 

构造函数中抛出异常会发生什么?

曾有人问了我个问题:如果在构造函数中抛出异常会怎么样?

现在可以回答了。

构造函数中抛出异常的主要问题是:当有多个资源分配时,如果出现异常,如何释放已经成功分配的资源。

下面是TCPL中推荐的一种方法:基本思想是将资源封装在对象中,然后将该对象以成员变量的形式聚合入你的类中。这个封装类在其析构函数中释放资源。这样,当你的类的构造函数中出现异常后,编译器会调用封装类的对象的析构函数,释放资源。

Continue reading “构造函数中抛出异常会发生什么?”

C++设计模式的新形式

最近再看WTL。C++模板带来的设计模式实现的改变,的确没那么容易很快接受。慢慢来吧。

上面是一个实验:一个采用继承实现多态,另一个采用模板实现的多态。
前者称为动多态(Dynamic Polymorphism),后者称为静多态(Static Polymorphism)

下面是汇编代码上的差别,静多态没有使用虚函数,所以代码要少一些。

动多态Imple* impl所指类型是在运行期时确定的,上图中多出的代码就是通过虚函数表查找合适的函数指针。静多态的这个确定过程是在编译期完成的。编译器会用模板参数(TA,TB)代替Impl,从而生成的代码直接指向被调用的函数,也没有虚函数表的查找过程。

从类图上来看,静多态是平面的,不像动多态有继承层次。这也是习惯了OO思想后不容易理解的。

又见虚函数

前几天我的一个同学在IBM笔试中遇到一道C++题,大概意思就是:

#include <stdio.h>
class Base {
    virtual void f(int i){printf("Base");}
};
class Derive { //补充!注意,这里没有继承Base
public:
    virtual void f(int i){printf("Derive");}
};

int main(int,char**)
{
    Derive* pd = (Derive*)new Base;
    pd->f(1);
    return 0;
}

What is the output?

要是将Base中的f(int i)改成 anything(int i)就更有难度了。

#include <stdio.h>
class Base {
  virtual void func(int i) { printf("base!!!
"); }
  virtual void f(int i) { printf("base..."); }
};
class Derive {
 public:
  virtual void f(int i) { printf("derive..."); }
  virtual void func1(int i) { printf("derive!!!
"); }
};
int main() {
  Base b, *pb;
  Derive d, *pd;
  pd = (Derive *)new Base;
  pd->func1(1);
  return 0;
}

输出:Base…

编译器只是取出对象的vftable然后找到虚函数表首地址,然后“偏移”,然后调用。
根本不管调用函数的名字、参数列表和访问权限。如果恰巧参数列表中的参数在栈中的大小一样,那就成功调用了,如果不一样,就会出现运行时错误(检查堆栈时报错)

c++陷阱之临时变量

先看代码:

我们开始都会认为在调用Say()之后,对象d的m_b成员变量会被修改为7但是结果却输出“1”,原因如下:

50,51行处出现了一个$T563,这其实是一个C++生成的临时对象汇编代码

37,38行如下:

37 _d$ = -8      
38 $T563 = -12
( sizeof(Derived)==8, sizeof(Base)==4 )

上面

mov eax,DWORD PTR _d$[ebp]
mov DWORD PTR $T563[ebp],eax

这段代码是将对象d的内容拷贝到临时变量中,并且只拷贝Base中有的部分,这样做
就是所谓的“Slicing”。有些书中说这一步是由拷贝构造函数完成的。概念上是这样的,
但是实际上,编译器并没有生成一个真正意义上的拷贝构造函数。

这更进一步说明C++产生了一个临时对象作为强制转换的中间结果。然后以这个临时
对象代替我们的对象d,来调用函数Say()。那么结果自然是,临时变量的m_b被改变,
而我们的d.m_b没有发生变化

这种强制类型转换就是所谓的"向上转型",upcasting。 也叫Object Slicing。这种操作应该避免使用

C++、Java类方法绑定方式对比

c++,java 动态绑定和静态绑定的对比

/* a.cpp */
#include <iostream>
using namespace std;
class Base
{
    public:
        virtual void method1(){cout<<"Base Method1"<<endl;};
        method2(){cout<<"Base Method2"<<endl;};
};
class Derived:public Base
{
    public:
        void method1(){cout<<"Derived Method1"<<endl;}
        void method2(){cout<<"Derived Method2"<<endl;}
};
int main(int argc,char** argv)
{
    Base *b = new Derived();
    b->method1();
    b->method2();
    delete b;
    return 0;
}

Output:

Derived Method1
Base Method2
/* A.java */
class A
{
    public void method1(){
        System.out.println("Base method1");
    }
    public void method2(){
        System.out.println("Base method2");
    }
    public static void main(String[] args){
        A a = new B();
        a.method1();
        a.method2();
    }
};
/* B.java */
class B extends A
{
    public void method1(){
        System.out.println("Derived method1");
    }
    public void method2(){
        System.out.println("Derived method2");
    }
}

Output:

Derived method1
Derived method2

从上面的对比中可以看出

c++中要覆盖父类的方法,必须再父类的被覆盖的方法前加virtual,即将改方法声明为虚函数,这样c++编译器会产生一个虚函数表

java中如果子类中的方法名和参数列表与父类中的相同,则父类的方法自动被覆盖,不需要做而外的声明

java中默认是动态绑定或叫晚绑定,所以java中要引入 final 关键词以禁止默认的动态绑定

c++中默认是静态绑定或叫早绑定,所以c++要引入 virtual 关键词以支持动态绑定

Posts navigation

1 2
Scroll to top