对于我的优化,我想得到一个不错toupper
的Rcpp。我是C ++的新手,据我所知:
#include <Rcpp.h>
using namespace Rcpp;
void C_toupper_String(const String& s) {
for (char *p =(char *)s.get_cstring();*p!=0;p++) *p = toupper(*p);
}
// [[Rcpp::export]]
StringVector C_toupper(StringVector const& vecteur) {
StringVector res=clone(vecteur);
for (int i(0); i < res.size(); ++i) {
C_toupper_String(res[i]);
}
return res;
}
/*** R
teststring <- "HeY I arNaud"
C_toupper(teststring)
toupper(teststring)
identical(C_toupper(teststring),toupper(teststring))
*/
但是,它不能正常工作。
> C_toupper(teststring)
[1] "HEY I ARNAUD"
> toupper(teststring)
[1] "HEY I ARNAUD"
> identical(C_toupper(teststring),toupper(teststring))
[1] FALSE
有什么问题?如果可能的话,我不想转换String
为std::string
,因为我想了解发生了什么:进入C ++的目的是能够避免复制和转换。
谢谢,
阿诺
为什么两个字符串不测试identical
的问题很难解释-两个字符串在检查其原始字节时(通过charToRaw
)肯定看起来相同,它们不携带属性,并且没有编码集。因此,实际上,它们应该相同。
为了解决这个难题,我们需要了解您的C ++代码实际上在做什么。更具体地说,C风格的强制转换C_toupper_String
正在做什么。因为他们危险的,你应该永远使用C-风格的转换。您的代码纯粹是由于这种转换而出现问题。
为什么?因为String::get_cstring
回报char const*
。您将其char*
抛弃,从而抛弃其const
本质。这可能是安全的,但只有在底层存储不是const
。否则,它是未定义的行为(UB)。由于代码重写(例如优化),UB的效果很难预测。在这种情况下,似乎会产生使R字符串内部混乱的代码。
从根本上讲,您不能Rcpp::String
在适当位置修改对象,而它们不允许这样做。但是,如果您只是想避免复制,那么您的代码无论如何都无法实现其目标,因为您的C_toupper
函数会在第一步中明确复制输入。
正如Dirk所说,解决此问题的正确方法是使用可用的Rcpp API。对于字符串修改,这意味着将您的输入转换为std::string
,执行修改,然后再转换回。这确实会复制,但是您当前的代码也会复制。这是编写此代码的一种好方法:
#include <Rcpp.h>
#include <cctype>
#include <string>
// [[Rcpp::export]]
Rcpp::StringVector C_toupper(Rcpp::StringVector const& vec) {
std::vector<std::string> res(vec.begin(), vec.end());
for (std::string& str : res) {
for (char& c : str) c = std::toupper(c);
}
return Rcpp::wrap(res);
}
注意,这将有时会产生错误的结果,因为std::toupper
从根本不能与某些Unicode的特性处理。R的toupper
效果更好,但也有一些问题。甲合适溶液是使用{stringr}或{stringi}包。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句