如何分配字符串文字

时间:2017-03-21 15:07:40

标签: c++ string c++11 c++14

我是Java程序员;我20年前写过C或C ++。现在我回来了,我正在尝试使用更现代的C ++,比如C ++ 11 / C ++ 14,以避免旧的c风格编程。

如何分配字符串,如Java:

private static final String MY_STRING = "Hello World"; // could also be public

现在我对文字MY_STRING提供了"Hello World",我可以在我的计划中多次使用,如果我希望将其更改为"Hello Dolly" ,我完全在一个地方做了改变。

我想在C ++中实现相同的目标。 例如:

JavaVMOption* options = new JavaVMOption[1];

options[0].optionString = (char *)"-Djava.class.path=.";

这有效,不再有问题,但我不喜欢它,因为只有在需要时才能在一个地方更改它。 所以,我宣布(即使在头文件中):

std::string classpath = "-Djava.class.path=.";
// or
const std::string classpath = "-Djava.class.path=.";

我用它作为:

options[0].optionString = (char *)classpath.c_str();

现在,使用c_str()函数,这也有效,但我回到原来的老C!

我真的想知道是否有理由保持更现代的C ++级别?

是的,我知道,

JavaVMOption* options = new JavaVMOption[1]; 

按原样声明,我无法更改它。但即使在C ++中,使用引用而不是在给定的情况下使用指针也是一个好主意,就像在Java中一样。有解决方案吗?我找不到一个。

1 个答案:

答案 0 :(得分:2)

"Hello"是6 charH e l l o {{1}的const缓冲区分别是其生命周期是整个程序。

\0

将该缓冲区复制到std::string bob = "Hello"; 对象中。 std::string是一个值语义对象;这是Java往往缺乏的东西,因为所有对象都是通过引用隐式传递的。

std::string
这是非常危险的。您将该缓冲区转换为指向options[0].optionString = (char *)"-Djava.class.path=."; 的非const指针,然后将其指定给char

我不知道optionString是什么,但如果它是optionString类型的变量,那么这将打开未定义的行为。对缓冲区char*的任何编辑都是未定义的行为,并且将非"-Djava.class.path=."指针存储到这样的缓冲区只是要求它发生。

简而言之,const的类型是危险的关键。它只是鲁莽,还是真的很蠢?

optionString

这会在堆上创建一个大小为JavaVMOption* options = new JavaVMOption[1]; 的{​​{1}}数组,然后存储指向JavaVMOption中第一个元素的指针。

这里有很多毫无意义的事情。并且摧毁它需要将其作为阵列销毁?

1

这会在堆栈上创建一个名为options的{​​{1}}。它会在范围结束时自动销毁。这似乎更实际。除非您需要JavaVMOption options; ,否则使用JavaVMOption毫无意义,而您在C ++中很少需要options

我找到了一些示例代码:

new

并不是那些用C ++编程为生的人写的。

这是我最初的尝试:

new

使用:

new

通过使用#include <jni.h> /* where everything is defined */ ... JavaVM *jvm; /* denotes a Java VM */ JNIEnv *env; /* pointer to native method interface */ JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */ JavaVMOption* options = new JavaVMOption[1]; options[0].optionString = "-Djava.class.path=/usr/lib/java"; vm_args.version = JNI_VERSION_1_6; vm_args.nOptions = 1; vm_args.options = options; vm_args.ignoreUnrecognized = false; /* load and initialize a Java VM, return a JNI interface * pointer in env */ JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); delete options; /* invoke the Main.test method using the JNI */ jclass cls = env->FindClass("Main"); jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V"); env->CallStaticVoidMethod(cls, mid, 100); /* We are done. */ jvm->DestroyJavaVM(); struct destroy_java_vm { void operator()(JavaVM* jvm)const{ jvm->DestroyJavaVM(); } }; using up_java_vm = std::unique_ptr< JavaVM, destroy_java_vm >; struct java_vm { up_java_vm vm; JNIEnv* env = 0; }; struct java_vm_option { std::string string; std::shared_ptr<void> extra_info; }; using java_vm_options = std::vector<java_vm_option>; struct java_vm_init { unsigned version = JNI_VERSION_1_2; java_vm_options options; bool ignore_unrecognized = false; java_vm init() { std::vector<JavaVMOption> java_options(options.size()); for (std::size_t i = 0; i < options.size(); ++i) { java_options[i].optionString = &options.string[0]; java_options[i].extraInfo = options.extra_info.get(); } JavaVMInitArgs args; args.version = version; args.options = java_options.data(); args.nOptions = java_options.size(); args.ignoreUnrecognized = ignore_unrecognized?TRUE:FALSE; java_vm retval; JavaVM* tmp = 0; auto res = JNI_CreateJavaVM(&tmp, (void **)&retval.env, &args); if (res < 0) { return {}; // error message? How? } retval.vm.reset( tmp ); return retval; } } 对象是一个仅移动的值类型。当它被销毁时,java vm会自动销毁(如果你没有将它移出)。

在直接与API交谈时,我们必须转向C风格的代码,因为许多跨语言API是使用C风格的接口编写的。我们将C风格的界面包装成更安全,更易于使用的C ++类型。

未经测试的代码,可能包含拼写错误。