跟进函数重载的问题:
那么模板使函数重载变得不必要(在 C++ 中)?或者当模板不能替代函数重载时还有选择吗?
突然,一个奇怪的想法浮现在脑海。如果 Google Play Market 上有 Java 应用程序,那么理论上它应该可以在任何有 Java 机器的地方工作。它也应该适用于 Windows。
问题:
是否可以在 Windows 上从 Google Play Market 安装 Java 应用程序?
我远离网络编程,但该网站会定期提出有关如何制作“人类可读的 URL”的问题。
问题:为什么我们需要“人类可读的 URL”?有人进入网站后看地址栏吗?还是有人在地址栏中键入“人类可读的 URL”?
假设有一个程序:
int aaa;
class b {
int bb;
public:
b(){}
};
b bbb;
int main(){
return 0;
}
如您所知,在启动 main 之前,零将写入变量“aaa”。
问题:
PS这个问题不是闲着的。我们需要了解是否可以避免对静态对象进行强制归零,从而加快主函数的启动速度。
UPD1:
看起来需要做一些澄清。
这个问题与嵌入式系统的操作有关。也就是说,在这种系统中,代码被硬连线到 ROM 中并从 ROM 开始。在这样的系统中,不可能在启动时初始化静态变量,因为代码存在于 ROM 中,并且在启动时 RAM 中有垃圾。也就是说,没有
bbb:
.zero 4
aaa:
.zero 4
在这样的系统中不滚动。正是在 main 之前,必须运行单独的代码将静态变量重置为零。同时,如果重置静态变量的代码耗时过长,那么这也是不好的。有一次我与能源领域保护系统的开发人员进行了交谈。他们有一个要求,上电后保护开始工作的时间不迟于50Hz工频的半个周期,即不迟于10毫秒(如果线路短路挂断设备,则关闭设备)。如果电源打开,并且处理器用零填充静态变量而不是工作,那么这不是很好。
因此,问题出现了——如何控制将静态变量归零的过程以及是否可以使用具有空构造函数的类来完成。至少对于 GCC 和 clang 来说,这似乎是不可能的。
如何确保通知权限窗口永远不会出现在 Chrome 浏览器中?不是一个站点。也许需要安装某种插件,或者设置中的某处有关闭?是否可以完全禁用此窗口,或者 Google 是否坚持我每次都手动拒绝站点通知?
例如,考虑 Windows。
如您所知,翻译器可以通过寄存器或堆栈将参数传递给函数。当整个项目使用相同的广播密钥进行广播时,一切都清楚了。但是,比如项目有一个*.lib库,通过寄存器接受一些函数的参数,整个项目通过堆栈接受函数参数。编译器如何理解某些库函数需要以不同方式调用?
我写了一个函数模板:
template <class T> void fun(T tt){
//здесь какая-то работа с tt
}
现在我想如果类型 T 很小,那么在实例化参数时,应该按值传递:
void fun(little_struct tt){
//здесь какая-то работа с tt
}
如果类型 T 很大,那么在实例化期间通过引用传递参数:
void fun(big_struct& tt){
//здесь какая-то работа с tt
}
问题:
编译器 VS2017。
有一个有效的代码:
#include "pch.h"
#include <iostream>
using namespace std;
template <class T> class a {
int aint;
T* tptr;
public:
a(T* ptr1) :tptr(ptr1) {}
};
class b:public a<b> {
int bint;
public:
b() :a(this) {}
void print() { cout <<endl<<"run class b"; }
};
int main()
{
cout << endl<<"Hello World!";
b bb;
bb.print();
}
现在我想让它从类“b”传递this指针,而不是通过类“a”的构造函数,而是通过模板参数。我写的是这样的:
#include "pch.h"
#include <iostream>
using namespace std;
class b;
template <class T* ttptr> class a {
int aint;
T* tptr;
public:
a() :tptr(ttptr){}
};
class b :public a <this> {
int bint;
public:
b() {}
void print() { cout <<endl<<"run class b"; }
};
int main()
{
cout << endl<<"Hello World!";
b bb;
bb.print();
}
但是编译器发誓:
class b :public a <this>
问题:
在这里,和往常一样,在错误的时间,我想到了以下问题。从堆分配内存时,很明显堆必须存储有关所请求内存区域大小和所请求元素数量的信息。那么为什么会有单独的运算符deleteanddelete[]呢?毕竟,无论我们请求的是向量还是单个元素,堆都包含有关请求区域大小和请求元素数量的信息。不可能在请求堆中的一个元素时,没有存储请求一个元素的信息。如果是这种情况,那么操作员delete可以很好地确定(根据堆中包含的服务信息)是请求了一个数组还是请求了一个元素。并且,相应地,将一个元素或一个向量的内存返回到堆中。事实证明,运营商delete[]多余的。
UPD1:
在当前的方法中,C++ 更经济:它仅将其附加信息存储在具有非平凡析构函数的对象数组中。
所以你的意思是堆有几种格式?请求的单个元素的一种格式,请求的向量的另一种格式,具有非平凡分配器/析构函数的请求的单个元素的第三种格式,具有非平凡分配器/析构函数的请求向量的第四种格式?好吧,这取决于编译器和堆的开发人员,当然,他们如何看待自己的任务以使其尽可能高效。但乍一看,拥有许多堆格式并不比存储所有信息并在运行时弄清楚现在到底有什么更有效。此外,您仍然需要了解许多堆格式的运行时和方法。
UPD2:
是的,非平凡的分配器还存储有关请求元素的数量和堆中一个元素的大小的信息。有了这些信息,一个重要的析构函数就可以弄清楚它到底需要删除什么。同样,在这种情况下,不需要 delete[ 运算符,删除运算符就足够了。
UPD3:
现在让我们先不管非平凡的分配器。现在考虑标准分配器,特别是因为两种情况下的问题是相同的。
因此,有一个堆,并且有 new 和 new[] 运算符。两个算子都需要在堆的服务信息中输入一个对象的大小和请求中的对象数量数据。因此,只需要一个删除内存返回操作符,因为根据服务信息,运行时可以而且应该准确计算出请求了多少对象。因此,delete[] 运算符是多余的。
现在考虑非标准(自定义)分配器。同理,用户 new 和 new[] 需要将请求中的一个对象的大小和 NUMBER of OBJECTS 的数据输入到堆的服务信息中。此外,用户定义的 new 和 new[] 需要在堆开销中包含指向用户定义的析构函数的指针。同样,在这种情况下,只需要一个删除内存返回运算符,因为根据服务信息,运行时可以而且应该准确地计算出请求了多少对象。因此,delete[] 运算符是多余的。
我听说过关于 iOS 上没有 JVM 的可怕谣言。此外,我听到了可怕的谣言,说 Apple 不允许在 iOS 上安装 JVM。
问题:
记得在 Windows 出现之初,微软就大力提倡所谓的匈牙利符号。此外,许多编程公司已经将这个工具作为解决所有开发问题的灵丹妙药。
问题 - 我们现在有什么匈牙利符号?死了,没死?微软对此有何看法?有任何官方/非官方建议吗?
UPD1:
这里的同事都归结为匈牙利符号允许变量名具有变量类型的事实。但事实并非如此。如果有人需要在变量名中包含这个变量的类型,那么这个就很简单了。您只需要在变量名称中包含变量的类型。不仅仅是“a”,还有“a_int”。另一方面,匈牙利符号声称是对呼叫功能的描述。对于 WinAPI 和 MFC 函数尤其如此。所以事实证明 GetDataFromPromDromStrem 这只是最体面的。小写和大写字母组成的栅栏据说使程序维护更容易。没有多少年过去了,似乎连微软都不记得这种工艺了。
UPD2:
然后我就纳闷了,就去俄罗斯维基百科。不,他们什么也没听到。
说到这里,我已经不解了,就去俄罗斯维基百科。是的,他们听说了。
应用程序的有意义的前缀
匈牙利符号:Префикс Сокращение от Смысл Пример i index Индекс int ix; Array[ix] = 10; d delta Разница между значениями int a, b; ... dba = b - a; n number Количество size_t nFound = 0; a argument Аргумент SomeClass::SomeClass(int aX) : x(aX) {}
这是 SO 网站上一个过于聪明的格式化程序,它删除了字符串中的空格,因此无法迁移表。但是您可以查看俄语维基百科。
一般来说,没有人会说 delta 或 number 是变量类型。这不是一种类型,而是一种可变功能。此外,这种方法被转移到对 WinAPI 的调用中,在那里,在每个调用名称中,他们都试图坚持这个调用的功能。
有一个简单的测试程序:
// Example program
#include <iostream>
#include <string>
using namespace std;
class a1 {
public:
void printid() { cout << endl << "this is a1 id"; }
};
class a2 : public a1 {
public:
void printid() { cout << endl << "this is a2 id"; };
};
int main() {
a1 aa1;
a2 aa2;
a1* aa1_ptr = &aa1;
a2* aa2_ptr = &aa2;
a1* aa1_ptr_derived = (a1*)aa2_ptr;
aa1.printid();
aa2.printid();
aa1_ptr->printid();
aa2_ptr->printid();
aa1_ptr_derived->printid();
return 0;
}
这个程序的输出是:
this is a1 id
this is a2 id
this is a1 id
this is a2 id
this is a1 id
如果您将 printid() 函数设为虚拟,则结果会发生显着变化。
即,如果程序是:
// Example program
#include <iostream>
#include <string>
using namespace std;
class a1 {
public:
virtual void printid() { cout << endl << "this is a1 id"; }
};
class a2 : public a1 {
public:
virtual void printid() { cout << endl << "this is a2 id"; };
};
int main() {
a1 aa1;
a2 aa2;
a1* aa1_ptr = &aa1;
a2* aa2_ptr = &aa2;
a1* aa1_ptr_derived = (a1*)aa2_ptr;
aa1.printid();
aa2.printid();
aa1_ptr->printid();
aa2_ptr->printid();
aa1_ptr_derived->printid();
return 0;
}
这个程序的输出是:
this is a1 id
this is a2 id
this is a1 id
this is a2 id
this is a2 id
也就是说,当我尝试从通过将派生指针转换为基类获得的基类指针调用虚函数时,将调用派生类虚函数。
问题:
UPD1:
对不起,同事们,我彻底钝化了。我不会删除问题,让它挂在学生的恐惧。只是通常在设计时,我从下往上查看层次结构,并希望获得指向基类的指针的多态行为。他确实明白了。然后出于某种原因,我从上到下查看了层次结构,并出于某种原因决定在降低层次结构时,我应该接收基类的所有属性。
我用 C/C++ 编写,但我看到带有垃圾收集的语言越来越受欢迎。再次,厌倦了寻找内存泄漏。在这方面,问题是:
碰巧我在 C/C++ 中工作了很多,而没有在 Java 中工作。现在,我看到移动平台对 Java 的需求很大。作为一个相当懒惰的人,我想避免完全学习 Java。我想继续用 C++ 编写,但不是将 C++ 代码翻译成本机代码,而是翻译成 Java 机器的代码。
问题:
UPD1:
根据我的概念,Java 代码现在被翻译成抽象 Java 机器的一些中间代码。在不同的平台上,有一个 JIT 转换器,当此代码运行时,将其转换为该平台的本机代码并启动它。还是我错了?
UPD2:
这似乎是一件容易的事。拿 GCC 翻译器,离开解析器,代替 x86 平台的代码生成器,为 Java 机器编写代码生成器。还没有人制造过这样的混合动力车吗?
UPD3:
然后是第二个问题,与第一个有关:
问题:
曾几何时,在 C++ 中,可以为方法/函数指定 nothrow 规范。这表明该方法/函数不会抛出异常。
作为一个有纪律的用户,我尝试在我的时间使用这个规范。但很快就发现,在开发过程中,跟踪哪些函数抛出异常以及哪些函数没有抛出异常是非常乏味的。我不再指定 nothrow。
现在有一个项目,原则上不会产生异常。结果,问题出现了。
问题:
标准当前支持 nothrow 吗?
现在标准中推荐使用 nothrow 吗?或者,就像新 C++ 经常出现的情况一样,它已被弃用。
nothrow 规范有什么用?使用 nothrow 规范时,编译器可以生成更快/更紧凑的代码吗?还是没有区别?
是否可以立即告诉翻译器所有类方法都有 nothrow 规范?为了不弄乱每种方法,也不要在其中指定 nothrow。
有一台笔记本ACER Pentium 四核,相当新(两年半前买的CPU N3540)。它运行的是 Windows-8,购买后升级到Windows-10-64 家庭版。Windows-10-64 家庭版会定期下载更新。
系统有4个磁盘:
我定期将某个文件夹从磁盘备份C:\到磁盘E:\和F:\. 文件夹很大,大约60个演出。我愚蠢地手动进行备份,因为这种情况很少发生。在备份之前,我从驱动器 E:\ 和 F:\ 中删除了文件夹的旧副本。
所以,问题是:
从 E:\ 驱动器中删除文件夹的旧副本时,旧副本会落入垃圾箱。
从 F:\ 驱动器中删除文件夹的旧副本时,旧副本不会落入垃圾箱。系统提示文件夹太大,无法放入垃圾箱,想立即删除。
同时,驱动器 E:\ 和 F:\ 上的文件夹副本是相同的。
是的,当然,在这两种情况下,我都会在删除操作之前清空篮子。
问题:
PS直到最近,当文件夹较小时,大约 40 gigs,在这两种情况下,系统都会报告文件夹太大而无法放入垃圾箱。
但是,最近,在安装了 Microsoft 的下一个更新后,系统的行为发生了变化,E:\ 驱动器中的文件夹开始被放入垃圾箱。而从F:\驱动器中删除相同的文件夹时,系统仍然报告该文件夹太大而无法放入垃圾箱。
Windows-10 中有一个从命令行启动的触摸实用程序。她可以更改文件的日期和时间。
您需要相同的实用程序(也从命令行启动),它可以更改文件夹(目录)的日期和时间。
告诉我在哪里挖。不要自己编写这样的实用程序。
【为什么要更改创作日期】我解释一下。在批处理文件中创建一个包含文件的目录块,然后将该块压缩并发送给客户。zip 中的所有文件和所有目录都必须具有此 zip 的相同日期和时间。这样客户就可以区分版本和版本的交付日期(除了实际的版本号)。
有一台笔记本电脑宏基奔腾四核相当新(CPU N3540 两年半前买的)。购买后运行Windows-8,升级到Windows-10-64家庭版。Windows-10-64 会定期下载更新。最近还有一个更新。系统现在显示 Windows 10 版本 1803 和内部版本号 17134.48。
但并非一切都那么顺利。安装此最新更新后,出现了一个令人不快的功能:开始工作时,开机大约十秒钟后,出现一条消息,提示CD驱动器D:\已满,建议清理其上不必要的文件。将出现一个清理面板,其中所有额外文件都显示为空。如果您同意并单击“确定”,则该面板将消失,并且在下次重新启动机器之前不会再次出现。
但是,CD 媒体 D: 中没有插入任何内容。
它不干扰工作,但有点烦人。
如何删除此错误消息,使其根本不出现?
如您所知,在 Windows 中,当您使用 USB 闪存驱动器完成操作时,您必须使用单独的命令禁用它。在此命令之后,会出现消息“现在可以移除 XXX 驱动器”。
我厌倦了每次都用单独的命令关闭 USB 闪存驱动器。我记得在使用软盘时,没有单独的命令来禁用它们。复制到软盘操作的结束意味着可以移除软盘。
问题:
如何做到这一点,以便您不必在 Windows 10 中使用单独的命令断开 USB 闪存驱动器?我希望,在使用软盘时,复制操作(读取或写入)的结束意味着可以移除 USB 闪存驱动器。
曾几何时(7 年前)我读过 Alexandrescu。我注意到他花了很多空间来创建单例。也就是说,这种类型的对象存在于程序中的单个实例中。
问题:
为什么我们需要这样的对象存在于程序中的单个副本中?
在程序中愚蠢地创建一次指定类型的对象而不再次创建这种类型的对象有什么问题?
任何类的静态成员都存在于程序中的单个实例中。这将检查翻译器和链接器,并在尝试创建静态类成员的第二个实例时引发错误。为什么任何类的静态成员都不是单例?
UPD1:
[@pepsicoca1,用代码解释问题的第三部分......你的意思并不完全清楚。]
迫于压力,我发布了构建一个以我命名的单身人士的秘密协议(我没有广播这个例子,这是一个即兴创作):
class shell_singleton;
clacc singleton{
friend shell_singleton;
private:
void method1(){/*some action*/}
void method2(int a){/*some action*/}
void method3(int a,float b){/*some action*/}
public:
};
class shell_singleton{
static singleton singleton_var;
public:
void method1(){singleton_var.method1();}
void method2(int a){singleton_var.method2(a);}
void method3(int a,float b){singleton_var.method3(a,b);}
};
singleton shell_singleton::singleton_var;
void main(){
shell_singleton shell_singleton_var;
shell_singleton_var.method1();
shell_singleton_var.method2(3);
shell_singleton_var.method3(5,10.1);
}
在这个例子中,shell_singleton::singleton_var 的一个实例;不能再次创建。
试图创建 shell_singleton::singleton_var; 将导致编译或链接错误。
不需要类实例化计数器。
一切都通过编译器和链接器解决。
同时,即使您创建了单例类型的实例,也无法使用它,因为它的所有方法都是私有的。
但是我玩得很安全,用户更容易根本不宣布单例类的存在,让他们使用 shell_singleton 类。
[@pepsicoca1,用代码解释问题的第三部分
你对前两部分有什么想法吗?然后由于某种原因,所有的大师都保持沉默,你可以看到没有人构建单例,亚历山德雷斯库在这个话题上被钉死在十字架上是徒劳的。无关主题可看。
其实我在另一个地方问过这个问题。这是查看讨论的链接:
http://www.cyberforum.ru/cpp-beginners/thread2205986.html
在那里,与stackoverflow不同,有几个答案。我不会说我的同事的论点使我相信构建单例的重要性。但至少是一些东西,至少是一些版本。
UPD2:
我在闲暇时想了想。好吧,程序员创建了一个单例。类型保护自己免受可怕的用户。用户获取并创建了一个 DLL,并在此 DLL 中创建了单例类型的第二个实例。没有编译器会跟踪这一点,因为 DLL 是单独翻译和链接的。然后你用单身人士为自己辩护的是什么?