我有一个类在其构造函数中调用内核,如下所示:
"ScalarField.h"
#include <iostream>
void ERROR_CHECK(cudaError_t err,const char * msg) {
if(err!=cudaSuccess) {
std::cout << msg << " : " << cudaGetErrorString(err) << std::endl;
std::exit(-1);
}
}
class ScalarField {
public:
float* array;
int dimension;
ScalarField(int dim): dimension(dim) {
std::cout << "Scalar Field" << std::endl;
ERROR_CHECK(cudaMalloc(&array, dim*sizeof(float)),"cudaMalloc");
}
};
Run Code Online (Sandbox Code Playgroud)
"classA.h"
#include "ScalarField.h"
static __global__ void KernelSetScalarField(ScalarField v) {
int index = threadIdx.x + blockIdx.x * blockDim.x;
if (index < v.dimension) v.array[index] = 0.0f;
}
class A {
public:
ScalarField v; …Run Code Online (Sandbox Code Playgroud) 在回答了这个问题而没有在标准文件中找到令人满意的答案后,我开始疑惑.该标准规定了以下wrt初始化提到的变量:
§6.7 [stmt.dcl] p4
[...]否则这个变量在第一次控制通过其声明时被初始化; 这样的变量在初始化完成后被认为是初始化的.如果通过抛出异常退出初始化,则初始化未完成,因此下次控制进入声明时将再次尝试初始化.
没有提到可能导致初始化被重试的情况,如果除了抛出异常之外的其他任何事情都失败了(longjmp()thead退出,信号等等).
我是否忽略了标准中的任何内容?我一遍又一遍地查看初始化,声明和异常条款,甚至通过快速搜索"静态"来查询CWG缺陷表,但找不到任何相关内容.
这是标准中的一个不明确的(并且作为这样的缺陷)吗?
以下两个函数产生不同的程序集,这告诉我它们是不同的.有人可以告诉我他们的不同之处是什么?并且函数本地静态变量初始化在func2线程安全与否?如果答案取决于编译器,我想知道最常见的编译器如何使用func2.
int func1(int val)
{
const auto impl = [](int v)
{
return v * 10;
};
return impl(val);
}
int func2(int val)
{
static const auto impl = [](int v)
{
return v * 10;
};
return impl(val);
}
Run Code Online (Sandbox Code Playgroud) 我想知道是否可以确保只在程序的静态初始化步骤中调用函数?
举个例子,假设我有一些包含一个std::map对象的单例类,并公开它的方法insert和at方法.我想确保从它(该at方法)读取数据是线程安全的,据我的理解,这需要确保没有任何东西正在修改数据(即使用该insert方法).
该映射仅在静态初始化期间填充,此时我假设只有一个线程.有什么方法可以确保insert一旦main()开始没有误导用户呼叫?
示例代码
#include <map>
#include <string>
class Singleton {
private:
std::map<std::string, std::string> m_map;
public:
static Singleton& instance() {
static Singleton theSingleton;
return theSingleton;
}
static bool insert(const std::string& key, const std::string& value) {
return instance().m_map.insert(std::make_pair(key, value) ).second;
}
static std::string at(const std::string& key) {
return instance().m_map.at(key);
}
};
static bool inserted = Singleton::insert("Hello", "World"); // fine
bool addItem(const std::string& key, const std::string& …Run Code Online (Sandbox Code Playgroud) 我管理一个开源项目,有一个用户报告了一种情况,根据 Java 的类中静态变量的初始化顺序,我认为这是不可能的。一个的价值static final类变量是不正确,显然是从一个依赖的静态方法的不同结果导致基于其自己的静态最终变量。
我想了解发生了什么,以便找出最佳解决方法。此刻,我很困惑。
我的项目的主要入口点是SystemInfo具有以下构造函数的类:
public SystemInfo() {
if (getCurrentPlatform().equals(PlatformEnum.UNKNOWN)) {
throw new UnsupportedOperationException(NOT_SUPPORTED + Platform.getOSType());
}
}
Run Code Online (Sandbox Code Playgroud)
单独运行时,问题不会重现;但是当作为正在执行的许多测试的一部分运行时,一个更大的构建 ( mvn install) 它始终是可重现的,这意味着问题可能与多线程或多个分叉有关。(澄清:我的意思是同时初始化两个不同类中的静态成员,以及与此过程相关的各种 JVM 内部锁定/同步机制。)
他们收到以下结果:
java.lang.UnsupportedOperationException:不支持操作系统:JNA 平台类型 2
此异常意味着SystemInfo实例化开始时有两件事是正确的:
getCurrentPlatform()是枚举值PlatformEnum.UNKNOWNPlatform.getOSType()是2不过,这种情况应该是不可能的;值 2 将返回 WINDOWS,而 unknown 将返回一个非 2 的值。因为两个变量都是static和final它们永远不应该同时达到这个状态。
我试图自己重现这个并失败了,我依赖于用户在他们的基于 Kotlin(kotest)框架中执行测试的报告。
用户的 MCRE 只需调用此构造函数作为在 Windows 操作系统上运行的大量测试的一部分:
public class StorageOnSystemJava {
public StorageOnSystemJava(SystemInfo info) {
}
}
class StorageOnSystemJavaTest …Run Code Online (Sandbox Code Playgroud) 我有一个类,它持有大量生成的常量:
public class Constants extends SomeBaseClass {
// init() is defined in some base class...
public static final XXX KEY1 = init(...);
public static final XXX KEY2 = init(...);
public static final XXX KEY3 = init(...);
// ...
public static final XXX KEY2000 = init(...);
}
Run Code Online (Sandbox Code Playgroud)
当生成的常量数非常高时,这会导致静态初始化程序大于Java方法大小的上限(即> 64kb),从而导致编译器错误.一种解决方案是为块创建几个"块初始化方法",可以保证产生少于64kb的字节码,这样它们就适合于一种方法:
public class Constants extends SomeBaseClass {
public static XXX KEY1;
public static XXX KEY2;
public static XXX KEY3;
// ...
public static XXX KEY2000;
static {
initialise0001To1000();
initialise1001To2000();
}
private static void …Run Code Online (Sandbox Code Playgroud) java compiler-construction compiler-errors static-initialization
我记得几年前我使用静态初始化程序来调用类级别的设置操作.我记得它有非常奇怪的行为,我只是决定避开他们.也许是因为我弄乱了最上层的订单或成为新手.但我遇到了重新审视它们的需要,我想确保没有一种更简洁的方法.
我知道它不时髦,但我经常有数据驱动的类,它们维护从数据库导入的静态实例列表.
public class StratBand {
private static volatile ImmutableList<StratBand> stratBands = importFromDb();
private final int minRange;
private final int maxRange;
private static ImmutableList<StratBand> importFromDb() {
//construct list from database here
}
//constructors, methods, etc
}
Run Code Online (Sandbox Code Playgroud)
当我有几十个像这样的表驱动类时,这个模式非常简洁(是的,我知道它将类与一个数据/实例源紧密结合).
但是,当我发现Google Guava的优点时,我希望在发布特定事件时使用EventBus更新静态列表.我会创建一个静态的最终布尔变量,只是为了调用初始化注册的静态方法.
public class StratBand {
private static volatile ImmutableList<StratBand> stratBands = importFromDb();
private static final boolean subscribed = subscribe();
private final int minRange;
private final int maxRange;
private static ImmutableList<StratBand> importFromDb() {
//construct list from database here
}
//constructors, methods, etc
private …Run Code Online (Sandbox Code Playgroud) 我有两个函数本地静态对象,一个和两个.一个人的构造函数和析构函数都通过GetTwo()访问两个:
#include <iostream>
struct One;
struct Two;
const One& GetOne();
const Two& GetTwo();
struct Two {
const char* value = "It's two!";
Two() { std::cout << "Two construct" << std::endl; }
~Two() { std::cout << "Two destruct" << std::endl; }
};
struct One {
One() {
std::cout << "One construct" << std::endl;
const char* twoval = GetTwo().value;
std::cout << "twoval is: " << twoval << std::endl;
}
~One() {
std::cout << "One destruct" << std::endl;
const char* twoval = GetTwo().value; …Run Code Online (Sandbox Code Playgroud) 在最新版本的 gcc(或 clang)中编译此代码时 -std=c17 -pedantic-errors -Wall -Wextra
static const int y = 1;
static int x = y;
Run Code Online (Sandbox Code Playgroud)
然后我没有收到编译器诊断消息,即使我相当确定这不是有效的 C 而是约束违规。我们可以通过查看C17 6.7.9/4来证明它是不符合的:
约束
...
具有静态或线程存储持续时间的对象的初始值设定项中的所有表达式都应为常量表达式或字符串文字。
然后是关于常量表达式的定义,在这种情况下是整数常量表达式(6.6):
整数常量表达式应具有整数类型,并且只能具有整数常量、枚举常量、字符常量、结果为整数常量的 sizeof 表达式、_Alignof 表达式和作为强制转换的直接操作数的浮点常量的操作数。
最后是关于整数常量的定义(6.4.4.1/2):
整数常量以数字开头,但没有句点或指数部分。它可能有一个指定其基础的前缀和一个指定其类型的后缀。
因此,const int变量不是整数常量,也不是整数常量表达式。因此不是有效的初始化程序。这之前已经讨论过(例如这里),我认为已经确定这是不合格的。但是,我的问题是:
为什么 gcc 即使在严格模式下也选择不合规?
clang 显然一直不合规,但 gcc 从 7.3 版的合规变为 8.0 及更高版本的不合规。即使在没有-pedantic-errors.
似乎已经对这条消息做出了某种积极的、有意识的决定。为什么在 gcc 中完全删除它,为什么在严格模式下编译时不保留它-std=c17 -pedantic-errors?
inline考虑使用C++ 17 中的新变量功能声明的全局(命名空间范围)变量:
struct something {\n something();\n ~something();\n};\n\ninline something global;\nRun Code Online (Sandbox Code Playgroud)\n在 x86 上的 Clang 14 中,生成的用于在启动时初始化变量的程序集如下:
\n__cxx_global_var_init: # @__cxx_global_var_init\n push rbx\n mov al, byte ptr [rip + guard variable for global]\n test al, al\n je .LBB0_1\n.LBB0_4:\n pop rbx\n ret\n.LBB0_1:\n mov edi, offset guard variable for global\n call __cxa_guard_acquire\n test eax, eax\n je .LBB0_4\n mov edi, offset global\n call something::something() [complete object constructor]\n mov edi, offset something::~something() [complete object destructor]\n mov esi, offset global\n mov …Run Code Online (Sandbox Code Playgroud)