我讨厌打败一匹死马,也就是说,在过去的几天里,我已经阅读了很多关于使用单例模式的相互矛盾的文章。
这个问题不是一般来说哪个是更好的选择,而是什么对我的用例有意义。
我正在做的宠物项目是一个游戏。我目前正在处理的一些代码,我倾向于使用单例模式。
用例如下:
现在澄清一下,以上几个要求在访问之间共享状态。例如,记录器正在包装一个日志库并需要一个指向输出日志的指针,网络需要一个已建立的开放连接等。
现在,据我所知,更建议避免单身人士,所以让我们看看我们如何做到这一点。很多文章只是说在顶部创建实例并将其作为参数传递到需要的任何地方。虽然我同意这在技术上是可行的,但我的问题就变成了,如何管理潜在的大量参数?好吧,我想到的是将不同的实例包装在一种“上下文”对象中并传递它,然后执行类似context->log("Hello World"). 现在确定这还不错,但是如果您有这样的框架怎么办:
game_loop(ctx)
->update_entities(ctx)
->on_preupdate(ctx)
->run_something(ctx)
->only use ctx->log() in some freak edge case in this function.
->on_update(ctx)
->whatever(ctx)
->ctx->networksend(stuff)
->update_physics(ctx)
->ctx->networksend(stuff)
//maybe ctx never uses log here.
Run Code Online (Sandbox Code Playgroud)
你明白了......在某些领域,“ctx”的某些方面从未使用过,但你仍然坚持在任何地方传递它,以防你可能想使用记录器调试某些东西,或者稍后在开发中,您实际上需要网络或该部分代码中的任何内容。
我觉得上面的例子更适合全局可访问的单例,但我必须承认,我来自 C#/Java/JS 背景,这可能会影响我的观点。我想采用 C++ 程序员的心态/最佳实践,但就像我说的那样,我似乎找不到直接的答案。我还注意到,那些建议只将“单例”作为参数传递的文章只给出了非常简单的用例,任何人都会同意参数是更好的方法。
在这个游戏示例中,即使您不打算立即使用它,您也可能不想在任何地方访问日志记录。文件系统的东西可能已经结束了,但在你构建项目之前,很难说它何时/何地最有用。
我也是:
如果选项 1,从性能的角度来看,我应该切换到使用命名空间函数,并将“私有”变量/函数隐藏在匿名命名空间中,就像大多数人在 C 中所做的那样?(我猜性能会有小幅提升,但随后我将不得不在其中一些方法上调用“init”和“destroy”方法,而不能只允许构造函数/析构函数为我做这件事,仍然值得吗?)
现在我意识到这可能有点基于意见,但我希望当遇到更复杂/嵌套的代码库时,我仍然可以得到一个相对较好的答案。
编辑: 经过深思熟虑,我决定改用“服务定位器”模式。为了防止服务定位器的全局/单例,我正在制作任何可能使用从抽象基类继承的服务的东西,该抽象基类要求在构造时传递服务定位器。
我还没有实现所有的东西,所以我仍然不确定我是否会遇到这种方法的任何问题,并且仍然会喜欢关于这是否是单例/全局范围困境的合理替代方案的反馈。
我读过 Service Locator 也有点反模式,也就是说,我发现的许多示例都是用静态和/或作为单例实现的,也许像我所描述的那样使用它会删除导致它是一个反模式?
所以正如标题所示,我有一个使用临时数组的函数,我想从另一个数组中写入一个值,然后将这两个值与它自身相乘.
例:
float[] a = {0, 0}
a[0] *= a[0] = b[n ];
a[1] *= a[1] = b[n + 1];
Run Code Online (Sandbox Code Playgroud)
我希望上面会做到以下几点:
a[0] = b[n ];
a[0] *= a[0]; //(aka: a[0] = a[0] * a[0])
a[1] = b[n + 1];
a[1] *= a[1];
Run Code Online (Sandbox Code Playgroud)
虽然这种行为似乎并没有发生.相反,它似乎只是乘以"a"中的原始值与"b"中保存的任何值相乘,如下所示:
a[0] = a[0] * b[n ];
a[1] = a[1] * b[n + 1];
Run Code Online (Sandbox Code Playgroud)
总是我的理解是,首先评估"="之后的任何内容,如下所示:
float a, b;
a = b = 5;
//"a" and "b" both equal "5" now.
Run Code Online (Sandbox Code Playgroud)
既然如此,是不是表明我原来的例子应该有效?
任何人都可以解释发生了什么以及为什么这段代码无法正常工作?
代码:
int a = 0;
a = ++a % 5;
Run Code Online (Sandbox Code Playgroud)
引起警告:
warning: operation on 'a' may be undefined [-Wsequence-point]
a = ++a % 5;
~~^~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
与各种编译器一起使用时,例如gcc -Wall
这段代码行得通吗?
int a = 0;
a = (a + 1) % 5;
Run Code Online (Sandbox Code Playgroud)
为什么这是警告,并且可以安全地忽略它?
将其包装在方括号等中似乎并不能消除警告。
编辑:为澄清起见,当我看到这些警告消息时,我正在使用C ++ 17编译器。
所以我不知道这是否可行,但是我的设置看起来有点像:
template <class T>
struct Something;
struct Example {
//not sure how this should be defined
//I was thinking void*, but I can't use pointers as the 'Something' class moves around the instances
//and I don't want to have to constantly update the pointers.
std::vector<?> addedTypes;
template<typename T>
void addThing() {
addedTypes.push_back(T);
Something<T>::addThing(*this);
}
void destroy() {
for (auto T : addedTypes) {
Something<T>::removeThing(*this);
}
}
};
template <class T>
struct Something {
static void addThing(Example e) {/*...*/}
static void …Run Code Online (Sandbox Code Playgroud) 所以我试图制作使用输入html属性'pattern'的html表单,但是当我通过Vue.js组件这样做时,它会创建非常奇怪的行为.这是一个小提琴演示.
Vue.component('test', {
template:`<input type="text" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16}"
title="Must contain at least one number and one uppercase and lowercase letter, and be between 8 and 16 characters."/>`
})
Run Code Online (Sandbox Code Playgroud)
这里的模式正则表达式的细分(regex101示例).
现在,对于我的生活,我无法弄清楚为什么正常版本正确验证,但Vue版本没有.
我想知道是否有适当的方法可以做到这一点。
举个例子:
struct Test {
static std::array<unsigned, 123> data;
};
std::array<unsigned, 123> Test::data = {};
Run Code Online (Sandbox Code Playgroud)
如果我想将 中的所有元素设置为data某个值,例如 5。
我可以做这样的事情:
struct Test {
static std::array<unsigned, 123> data;
private:
static decltype(data) init_data_arr() {
decltype(data) arr = {};
arr.fill(5);
return arr;
}
};
std::array<unsigned, 123> Test::data = Test::init_data_arr();
Run Code Online (Sandbox Code Playgroud)
但随后我会分配额外的数组内存并对其进行复制,这似乎并不理想。
另一种内存密集程度较低的选项是这样的:
struct Test {
static bool is_init;
static std::array<unsigned, 123> data;
Test() {
if (!is_init) {
is_init = true;
data.fill(5);
}
}
};
bool Test::is_init = false;
std::array<unsigned, 123> Test::data = {}; …Run Code Online (Sandbox Code Playgroud)