对工作程序中自定义函数的未定义引用(C++ 和 RcppParallel)
Undefined reference to a custom function in a worker (C++ and RcppParallel)
我是 C++ 编程的新手,正在尝试通过 R 试验 Rcpp。
我创建了一个函数来从一个字符串中生成所有可能的 k-mers。它以它的串行形式运行良好:
#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
// using namespace Rcpp;
// [[Rcpp::export]]
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
但是,当我尝试在并行实现中使用此函数(使用 RcppParallel)时,代码如下:
#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
using namespace Rcpp;
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;
struct p_cpp_kmer : public Worker {
// input string
std::vector< std::string > seqs;
int k;
std::vector< std::string > cpp_kmer( std::string s, int k );
// destination list
List output;
std::string
sub_s;
// initialize with source and destination
p_cpp_kmer(std::vector< std::string > seqs, int k, List output)
: seqs(seqs), k(k), output(output) {}
// calculate k-mers for the range of sequences requested
void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}
};
// [[Rcpp::export]]
List par_cpp_kmer(std::vector< std::string > seqs, int k, bool v){
// allocate output list
List outpar(num_seqs);
int num_seqs = seqs.size();
// p_cpp_kmer functor (pass input and output matrixes)
p_cpp_kmer par_kmer(seqs, k, outpar);
parallelFor(0, num_seqs, par_kmer);
return wrap(outpar);
}
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
编译失败,出现:undefined reference to p_cpp_kmer::cpp_kmer(std::string, int)' 错误。
我知道它与 declaring/referencing 和 cpp_kmer 有关,但我无法弄清楚 where/how 这样做是否合适(由于我缺乏 C++ 知识).
非常感谢您。
您可能有针对不同结构(或在 public 命名空间中)的 cpp_kmer
的实现,但是您的结构 [=] 缺少成员函数 cpp_kmer
的实现13=]。您将必须添加如下实现:
std::vector< std::string > p_cpp_kmer::cpp_kmer( std::string s, int k ) {
// your implementation goes here
}
您的 p_cpp_kmer
结构声明了一个 cpp_kmer
方法,但它从未被定义。相反,后面定义的是自由函数 cpp_kmer
。
你声明这个方法
std::vector< std::string > cpp_kmer( std::string s, int k );
您似乎想使用它:
void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}
但是您在这里定义了自由函数 cpp_kmer
:
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
您可以删除结构中 cpp_kmer
方法的定义以便使用自由函数,或者实际定义它。
代码还有其他问题:
在您的 operator()
中您丢弃了结果。我想你的意思是用这个代替 output[i] = cpp_kmer(sub_s, k);
即使您执行上述代码也是不安全的,因为 output[i] = cpp_kmer(sub_s, k);
分配 R 对象(每个单独的 R 字符串和字符串向量),这不能在单独的线程中发生.
如果您真的想并行执行此操作,则需要确保不在工作线程中分配任何 R 对象。
此外,当您考虑使用 C++11 和底层的 tbb 库时,编写并行代码会容易得多 RcppParallel
。例如:
#include <Rcpp.h>
#include <RcppParallel.h>
using namespace Rcpp;
using namespace RcppParallel;
// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::plugins(cpp11)]]
using string_vector = std::vector< std::string > ;
using list_string_vector = std::vector<string_vector> ;
// [[Rcpp::export]]
list_string_vector par_cpp_kmer( string_vector seqs, int k, bool v){
int num_seqs = seqs.size() ;
list_string_vector out(num_seqs) ;
tbb::parallel_for( 0, num_seqs, 1, [&seqs,k,&out](int i){
std::string& s = seqs[i] ;
int seq_loop_size = s.length() - k+1;
std::vector<std::string> vec(seq_loop_size) ;
for ( int z=0; z < seq_loop_size; z++ ) {
vec[z] = s.substr( z, k );
}
out[i] = vec ;
}) ;
return out ;
}
这是假设 std::string
可以在单独的线程中分配:
> par_cpp_kmer( c("foobar", "blabla"), 3 )
[[1]]
[1] "foo" "oob" "oba" "bar"
[[2]]
[1] "bla" "lab" "abl" "bla"
我是 C++ 编程的新手,正在尝试通过 R 试验 Rcpp。 我创建了一个函数来从一个字符串中生成所有可能的 k-mers。它以它的串行形式运行良好:
#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
// using namespace Rcpp;
// [[Rcpp::export]]
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
但是,当我尝试在并行实现中使用此函数(使用 RcppParallel)时,代码如下:
#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
using namespace Rcpp;
// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;
struct p_cpp_kmer : public Worker {
// input string
std::vector< std::string > seqs;
int k;
std::vector< std::string > cpp_kmer( std::string s, int k );
// destination list
List output;
std::string
sub_s;
// initialize with source and destination
p_cpp_kmer(std::vector< std::string > seqs, int k, List output)
: seqs(seqs), k(k), output(output) {}
// calculate k-mers for the range of sequences requested
void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}
};
// [[Rcpp::export]]
List par_cpp_kmer(std::vector< std::string > seqs, int k, bool v){
// allocate output list
List outpar(num_seqs);
int num_seqs = seqs.size();
// p_cpp_kmer functor (pass input and output matrixes)
p_cpp_kmer par_kmer(seqs, k, outpar);
parallelFor(0, num_seqs, par_kmer);
return wrap(outpar);
}
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
编译失败,出现:undefined reference to p_cpp_kmer::cpp_kmer(std::string, int)' 错误。
我知道它与 declaring/referencing 和 cpp_kmer 有关,但我无法弄清楚 where/how 这样做是否合适(由于我缺乏 C++ 知识).
非常感谢您。
您可能有针对不同结构(或在 public 命名空间中)的 cpp_kmer
的实现,但是您的结构 [=] 缺少成员函数 cpp_kmer
的实现13=]。您将必须添加如下实现:
std::vector< std::string > p_cpp_kmer::cpp_kmer( std::string s, int k ) {
// your implementation goes here
}
您的 p_cpp_kmer
结构声明了一个 cpp_kmer
方法,但它从未被定义。相反,后面定义的是自由函数 cpp_kmer
。
你声明这个方法
std::vector< std::string > cpp_kmer( std::string s, int k );
您似乎想使用它:
void operator()(std::size_t begin, std::size_t end) {
for (std::size_t i = begin; i < end; i++)
sub_s = seqs[i];
cpp_kmer(sub_s, k);
}
但是您在这里定义了自由函数 cpp_kmer
:
std::vector< std::string > cpp_kmer( std::string s, int k ){
std::vector< std::string > kmers;
int seq_loop_size = s.length() - k+1;
for ( int z=0; z < seq_loop_size; z++ ) {
std::string kmer;
kmer = s.substr( z, k );
kmers.push_back( kmer ) ;
}
return kmers;
}
您可以删除结构中 cpp_kmer
方法的定义以便使用自由函数,或者实际定义它。
代码还有其他问题:
在您的
operator()
中您丢弃了结果。我想你的意思是用这个代替output[i] = cpp_kmer(sub_s, k);
即使您执行上述代码也是不安全的,因为
output[i] = cpp_kmer(sub_s, k);
分配 R 对象(每个单独的 R 字符串和字符串向量),这不能在单独的线程中发生.
如果您真的想并行执行此操作,则需要确保不在工作线程中分配任何 R 对象。
此外,当您考虑使用 C++11 和底层的 tbb 库时,编写并行代码会容易得多 RcppParallel
。例如:
#include <Rcpp.h>
#include <RcppParallel.h>
using namespace Rcpp;
using namespace RcppParallel;
// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::plugins(cpp11)]]
using string_vector = std::vector< std::string > ;
using list_string_vector = std::vector<string_vector> ;
// [[Rcpp::export]]
list_string_vector par_cpp_kmer( string_vector seqs, int k, bool v){
int num_seqs = seqs.size() ;
list_string_vector out(num_seqs) ;
tbb::parallel_for( 0, num_seqs, 1, [&seqs,k,&out](int i){
std::string& s = seqs[i] ;
int seq_loop_size = s.length() - k+1;
std::vector<std::string> vec(seq_loop_size) ;
for ( int z=0; z < seq_loop_size; z++ ) {
vec[z] = s.substr( z, k );
}
out[i] = vec ;
}) ;
return out ;
}
这是假设 std::string
可以在单独的线程中分配:
> par_cpp_kmer( c("foobar", "blabla"), 3 )
[[1]]
[1] "foo" "oob" "oba" "bar"
[[2]]
[1] "bla" "lab" "abl" "bla"