我可以编写一个库,以便在加载时首先生成一个数据集,该数据集稍后可以被其他函数访问吗?
Could I write a library such that when loaded it first generates a dataset which could later be accessed by other functions?
通常库的函数只在调用时执行(不像普通程序有像 main()
这样的入口点),但在这种情况下,我想发布一个需要数据集的库,数据集太大,最好自己生成。
这让我想知道我是否可以编写一个库,在加载时执行一个生成数据集的函数(可能保存在全局变量或 extern
变量中),以后可以被其他函数使用,类似以下内容:
// lib.hh
#pragma once
struct Data{}; // Data is a custom class for holding the data set
extern Data dataset;
// lib.cc
#include"./lib.hh"
Data gen() {
// Generates the data here
return result;
}
double find(double key) {
// Searches data within `dataset` that has `key` as its key
}
所以当在另一个程序中加载时,gen()
应该自动 运行(并且在任何其他函数之前),然后加载库的程序可以调用 find(double)
。
这样的库实现可行吗?或者我最好只召唤一个生成数据的子进程,然后通过管道检索结果?
对于这种情况,我建议使用 static 局部变量
//header
struct Data{
Data() {
//Complex intialization code goes here
}
};
Data& data_gen() {
static Data data;
return data;
}
//caller/main
auto Data = data_gen(); //Initialization code run once
auto Data2 = data_gen(); //Reuse the variable no more runs
即使不同的线程也可以调用那个 data_gen
函数,但当然他们应该只读它,不要写不同步的东西。所以我通常会给它一个 const 引用,因为共享可变数据,即通过全局变量的状态是非常非常糟糕的风格。
所以更喜欢
const Data& data_gen() {
static Data data;
return data;
}
但是尽管这种方法是最稳健的方法,通常你可以在主函数 运行 之前让它 运行,如果你是所谓的静态链接(classic/default/standardized C++ 中的方式),但如果你是 .so/.dll/.dylib 就不行:
//Header lib.hpp
#pragma once
#include <iostream>
namespace lib_name {
struct Data{
Data() {
std::cout << "Ctor\n";
}
double find(double key) const{
return 0;
}
};
extern const Data dataset;
void foo();
}
//lib.cpp
#include <lib.hpp>
namespace lib_name {
const Data dataset;
void foo() {
dataset.find(5);
}
}
//main
#include <lib.hpp>
int main() {
lib_name::dataset.find(4.2);
lib_name::dataset.find(4.2);
lib_name::foo();
}
你只会得到一个“Ctor”,在 main 之前,但如果你的数据生成很复杂但可以用 std::array
完成,为什么不让它更简单呢?
//header
#include <array>
namespace lib_name {
struct Data{
constexpr Data() {
d_[0] = 42;
}
double find(size_t key) const{
return d_.at(key);
}
std::array<double,5> d_{};
};
inline constexpr Data dataset;
void foo();//just for demonstration optional of course
}
//lib.cpp optional
#include <lib.hpp>
#include <iostream>
namespace lib_name {
void foo() {
std::cout << dataset.find(0) << "\n";
}
}
然后你的初始化代码是运行一次,但是被编译器编译了。然后它只保存结果。
通常库的函数只在调用时执行(不像普通程序有像 main()
这样的入口点),但在这种情况下,我想发布一个需要数据集的库,数据集太大,最好自己生成。
这让我想知道我是否可以编写一个库,在加载时执行一个生成数据集的函数(可能保存在全局变量或 extern
变量中),以后可以被其他函数使用,类似以下内容:
// lib.hh
#pragma once
struct Data{}; // Data is a custom class for holding the data set
extern Data dataset;
// lib.cc
#include"./lib.hh"
Data gen() {
// Generates the data here
return result;
}
double find(double key) {
// Searches data within `dataset` that has `key` as its key
}
所以当在另一个程序中加载时,gen()
应该自动 运行(并且在任何其他函数之前),然后加载库的程序可以调用 find(double)
。
这样的库实现可行吗?或者我最好只召唤一个生成数据的子进程,然后通过管道检索结果?
对于这种情况,我建议使用 static 局部变量
//header
struct Data{
Data() {
//Complex intialization code goes here
}
};
Data& data_gen() {
static Data data;
return data;
}
//caller/main
auto Data = data_gen(); //Initialization code run once
auto Data2 = data_gen(); //Reuse the variable no more runs
即使不同的线程也可以调用那个 data_gen
函数,但当然他们应该只读它,不要写不同步的东西。所以我通常会给它一个 const 引用,因为共享可变数据,即通过全局变量的状态是非常非常糟糕的风格。
所以更喜欢
const Data& data_gen() {
static Data data;
return data;
}
但是尽管这种方法是最稳健的方法,通常你可以在主函数 运行 之前让它 运行,如果你是所谓的静态链接(classic/default/standardized C++ 中的方式),但如果你是 .so/.dll/.dylib 就不行:
//Header lib.hpp
#pragma once
#include <iostream>
namespace lib_name {
struct Data{
Data() {
std::cout << "Ctor\n";
}
double find(double key) const{
return 0;
}
};
extern const Data dataset;
void foo();
}
//lib.cpp
#include <lib.hpp>
namespace lib_name {
const Data dataset;
void foo() {
dataset.find(5);
}
}
//main
#include <lib.hpp>
int main() {
lib_name::dataset.find(4.2);
lib_name::dataset.find(4.2);
lib_name::foo();
}
你只会得到一个“Ctor”,在 main 之前,但如果你的数据生成很复杂但可以用 std::array
完成,为什么不让它更简单呢?
//header
#include <array>
namespace lib_name {
struct Data{
constexpr Data() {
d_[0] = 42;
}
double find(size_t key) const{
return d_.at(key);
}
std::array<double,5> d_{};
};
inline constexpr Data dataset;
void foo();//just for demonstration optional of course
}
//lib.cpp optional
#include <lib.hpp>
#include <iostream>
namespace lib_name {
void foo() {
std::cout << dataset.find(0) << "\n";
}
}
然后你的初始化代码是运行一次,但是被编译器编译了。然后它只保存结果。