我最近(在基于C#的类中)了解到,在对象的构造函数中注册事件侦听器有时会被认为是危险的,因为在对象完全初始化之前,这些事件侦听器会被赋予对该对象的引用,并且可能(至少在理论上) )在构造完成之前尝试访问该对象.
根据我的理解,在构造完成之前访问对象可能会导致崩溃,至少在某些语言中...如果它不会导致崩溃,那么我们只关心注册发生在最后,所以我们的对象已经准备好了在我们注册听众时接收活动.
我现在开始使用新的Swing GUI,并注意到构建Swing GUI时我的标准做法是在构造函数中连接事件监听器.
在构造函数完成之前,似乎不太可能调用Swing组件的事件侦听器,因为它们可能在组件被添加到可见的Swing容器之前没有连线,这只能在构造之后发生.
那么,在Swing中工作时,有没有真正的理由避免这种反模式?如果是这样,最简单的方法是什么?
我知道类型this是prvalue("纯"rvalue)指针,并且它可以通过附加关键字成为指向const的指针和/或指向volatile的指针(影响对其实例变量的访问)const或者volatile它所属的函数定义的末尾.
我也知道this有时(错误地)将其描述为一个const指针,也许是为了说"你不能做出任务this".作为右值,它本质上是不可分配的,因此不需要constrvalue 的概念.
我也知道在C++ 11中,有些情况下rvalue或左值会影响调用解析,但我试图解决这些可能性,而且我不确定是否存在实际情况调用分辨率this是一个右值指针而不是一个const左值指针.
从程序员的角度来看,是否存在这种区别产生真正差异的情况,例如可以使用const左值指针而不能使用左值指针的上下文,其中可以使用左值指针不能使用const左值指针,或者差异会影响呼叫解决?
Java中可终结对象的讨论通常讨论当最终化对象(及其相关资源)无法快速被垃圾收集时发生的常见间接成本.
目前,我更感兴趣的是,无论是在内存方面还是在对象分配时间内,可实现的最终直接成本是什么.我已经看到在很多地方倾向于提到这种成本的存在,例如,Oracle关于最终化内存保留问题的文章指出:
当
obj被分配时,JVM内部记录中obj是终结.这通常会减慢现代JVM具有的快速分配路径.
JVM如何记录对象实例的最终结果,以及这样做的内存和性能成本是多少?
对于对我的具体应用感兴趣的人:
我们生产和保留了数百万个极其轻巧的物体; 添加一个指向这些对象的指针是非常昂贵的,所以我们已经做了相当多的工作来删除它们的指针,而是使用较小的数字ID打包到字段的一部分位.解包该数字允许从使用Map存储它们的池中检索具有该id的共享不可变属性.
剩下的问题是如何处理不再使用的属性值的垃圾收集.
已经考虑的一种策略是使用引用计数; 当创建对象并检索值的池化id时,该值的引用计数递增; 当它不再使用时,必须递减.
确保此减量发生的一个选项是添加以下finalize方法:
public void finalize() {
Pool.release(getPropertyId());
}
Run Code Online (Sandbox Code Playgroud)
但是,如果可最终化的行为意味着必须保留指向该对象的附加指针,那么对于该应用程序而言,可最终确定的前期成本将被认为是高的.如果它意味着必须分配额外的对象,那几乎肯定会过高......因此,我的问题是:最终化的直接前期成本是多少?
考虑以下结构初始化:
#include<stdio.h>
struct bar {
int b;
int a;
int r;
};
struct foo {
struct bar bar;
};
int main(int argc, char **argv) {
struct bar b = {1, 2, 3};
struct foo f = {.bar = b, .bar.a = 5 };
// should this print "1, 5, 3", "1, 5, 0", or "0, 5, 0"?
// clang on Mac prints "1, 5, 3", while gcc on Ubuntu prints "0, 5, 0"
printf("%d, %d, %d\n", f.bar.b, f.bar.a, f.bar.r);
return …Run Code Online (Sandbox Code Playgroud) 在Java程序员中众所周知,为了使双重检查锁定正常运行,必须声明变量volatile,并且同步对象的初始化是不够的.
意识可能主要是因为volatile关键字的语义在1.5中改变为包括"之前发生"关系,至少部分是为了使双重检查锁定安全; 根据我的理解,"发生在之前"关系意味着写入volatile变量会导致线程中的所有缓存变量被写入主内存,并且在从volatile变量读取后,所有缓存变量都被认为是陈旧的,并且必须是从主内存重新读取,以便在写入volatile变量之前写入的所有内容都保证在"稍后从该变量读取之前"发生.
Stack Overflow 似乎认为,对于C#来说,volatile双重检查锁定是不必要的(尽管有人担心这可能是特定于某些CPU或微软的实现),同时也认为Java synchronized语句的语义与 C#的语义完全相同lock声明,这表明在C#中也存在Java中发现的相同问题,除非在两种语言之间的双重检查锁定的语义中存在一些其他主要差异.
那么......哪个是正确的?C#中的双重检查锁定实际上比Java更危险吗?如果是这样,那么语言语义有何不同呢?
如果不是,没有具体可能出错的是volatile什么?volatileC#中的语义是否像Java一样建立了"发生在之前"的关系,因此双重检查锁定在C#中是安全的,volatile因为它在Java中是1.5?
class Test
{
public static void main(String[] args)
{
short s=2,s1=200,s2;
s2=s+s1; // error: "possible loss of precision"
System.out.println(s2);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么将短路添加两个短路的结果分配给编译错误?
在Scala中进行开发时,我似乎经常遇到白色空间问题,这些问题会对代码的含义产生意想不到的影响.
最近,我在尝试编写多行布尔表达式时出现问题,其中断行似乎导致编译错误,即
(oneVeryLongExpression < anotherVeryLongExpression) || ((a == b) && c);
Run Code Online (Sandbox Code Playgroud)
...编译得很好,但是,如果因为这些很长的表达而我很想分裂线...
(oneVeryLongExpression < anotherVeryLongExpression)
|| ((a == b) && c);
Run Code Online (Sandbox Code Playgroud)
...它没有编译,这让我感到意外.
我发现我可以通过在整个表达式周围添加一组额外的括号来解决这个问题:
((oneVeryLongExpression < anotherVeryLongExpression)
|| ((a == b) && c));
Run Code Online (Sandbox Code Playgroud)
...但我仍然想了解为什么Scala需要这个提示来忽略换行符.
在向另一个方向发展时我也遇到了问题:我偶尔将一个中等大小的Scala代码块转换为一组单行代码片段,以便将每个代码片段作为单行输入到不接受的基于Scala的shell中多行输入.
这是一个for-each的示例,我需要能够在我的shell中作为单行输入运行(对于那些对我正在做的事情感到好奇的人,我正在查看我的软件图表是否相等检查两侧的变量类型是否属于特定类型,以查找x.equals(y)应该使用的位置而不是:)x == y:
equalityChecks.foreach { node => {
var lhsFound = false;
var rhsFound = false;
breakable {
node.inEdges().foreach { edge => {
if (nodesOfTypeT.contains(edge.originNode())) {
if (edge.tagged(leftOperand)) {
lhsFound = true;
};
if (e.taggedWith(rightOperand)) {
rhsFound = true;
};
if (lhsFound …Run Code Online (Sandbox Code Playgroud)