从cppref所说的值初始化
如果T是没有默认构造函数的类类型,或者是用户提供或删除的默认构造函数,则该对象是默认初始化的 ;
但由于该类类型已删除默认构造函数,该对象如何进行默认初始化?
据我所知,类类型的默认初始化需要访问默认构造函数.如果我们有:
struct A {
A() = delete;
int k;
};
Run Code Online (Sandbox Code Playgroud)
然后A *a = new A;会失败,也会失败A* a = new A();.
但是A a{};没关系.但为什么?根据cppreference
否则,如果braced-init-list为空且T是具有默认构造函数的类类型,则执行值初始化.
为什么STL会为Allocator保留一个接口?以vector为例:
template<class T,class Allocator = std::allocator<T>>
class vector;
Run Code Online (Sandbox Code Playgroud)
因为我们有很多选择来分配内存和构造对象
operator new,delete,new[],delete[],这些对象几乎可以创建我们创建对象时所需的任何东西.
那么为什么STL容器vector需要一个Allocator接口,std::allocator如果我们不分配一个接口,那么它在大多数情况下是默认的?为什么不直接使用new表达式?
如果目的是使用户定义的分配行为成为可能,为什么不让用户提供自定义的operator new,new[]等等?
这是一个类似的问题,但是在这个问题中它有效,但是,它在以下情况下失败了,为什么?
namespace A
{
int k;
}
namespace B
{
class test{};
void k(const test&){/*do something*/}
}
int main()
{
using namespace A;
k(B::test());//compile error
}
Run Code Online (Sandbox Code Playgroud)
错误信息是: "'A :: k'不能用作函数"(gcc 6.3.0)
也就是说,编译器不会尝试执行ADL,也不会找到void k(const test&)innamespace B
但是,我认为ADL应该在这种情况下工作,因为上面的代码不属于以下情况:
引自cppref
首先,将参数相关的查找不被认为是如果通过通常的不合格查找产生的查找组包含任何以下的:
1)一个声明类成员
2)声明在块范围的函数的(这不是一个using声明)
3)任何声明这不是一个函数或函数模板(例如,功能对象或其他变量,其名称冲突与同时被查找的功能名称)
更确切地说,这里using namespace A 没有引入任何声明:
引自cppref
using-directive不会向它出现的声明区域添加任何名称(与using-declaration不同),因此不会阻止声明相同的名称.
据我所知,在 c++17 中,纯右值的概念/语义不再是临时对象,因此在许多情况下强制执行复制省略。
如果表达式是纯右值,则函数返回的对象将直接由该表达式初始化。当类型匹配时,这不涉及复制或移动构造函数
为什么“对象”一词出现在这里?在值类别中,不是引用类型的函数的返回属于纯右值,所以我认为使用术语对象可能是不合适的。
根据我的理解,纯右值现在不再是对象,它们只是值,对吗?
作为补充,这里也使用术语“对象”。
最近我正在研究操作系统,并遇到了这个问题.
线程是在C#用户级别还是内核级别创建的,如:
Thread mythread=new Thread(ThreadStart(something));
Run Code Online (Sandbox Code Playgroud)
据我所知,内核级别的cpu密集型线程的运行速度可能比用户级别的运行速度快. 因为现代操作系统这本书说"用户级线程的时间表不会陷入内核,这就是为什么它们与kernl级线程相比更轻量级".
所以我认为用户级线程无法在不同的cpu上运行,这需要陷入内核.
在linux中,创建的线程pthread_create是内核级别.所以我对.Net C#的功能感到好奇.
下面的代码示例来自一个介绍其效果的中文博客volatile.左边是C代码; 另一个是生成的汇编代码.
// cordering.c gcc -O2 -S -masm=intel cordering.c
int A;
volatile int B;
void foo() mov eax, DWORD PTR B[rip]
{ mov DWORD PTR B[rip], 0
A = B + 1; add eax, 1
B = 0; mov DWORD PTR A[rip], eax
} ret
Run Code Online (Sandbox Code Playgroud)
正如我们在汇编代码中看到的那样,副作用A放在副作用之后B,即使B是volatile合格的.但是,cppreference.com说:
[W]在单个执行线程中,易失性访问不能优化或重新排序,具有在易失性访问之前排序或排序的另一个可见副作用.
这里的副作用A之前是排序的B,所以我认为编译器执行此操作是非法的.我对吗?
作为补充,博客说如果我们想要保证a volatile和non-volatiletype 之间的顺序,我们需要同时做到volatile:
// cordering.c gcc …Run Code Online (Sandbox Code Playgroud) 例如:
#include<iostream>
using namespace std;
class A
{
public:
A(){cout<<k<<endl;}//make some output
static int k;
};
A a;//before `k`'s definition
int A::k=666;
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
答案是否保证是666(我在 gcc8.1.0 中测试过,答案是666)或导致未定义的行为?
更重要的是,在这个例子中,对象a和定义A::k在同一个翻译单元中,如果它们在不同的单元中会发生什么,因为
不同翻译单元中静态变量的初始化是不确定顺序的
从我的角度来看,由于在同一个 TU 中初始化顺序是固定的,因此上面示例的答案应该是无限制的。
在这里,我编写了一个代码片段来查看哪个swap将被调用,但结果都不是.什么都没输出.
#include<iostream>
class Test {};
void swap(const Test&lhs,const Test&rhs)
{
std::cout << "1";
}
namespace std
{
template<>
void swap(const Test&lhs, const Test&rhs)
{
std::cout << "2";
}
/* If I remove the const specifier,then this will be called,but still not the one in global namespace,why?
template<>
void swap(Test&lhs, Test&rhs)
{
std::cout << "2";
}
*/
}
using namespace std;
int main()
{
Test a, b;
swap(a, b);//Nothing outputed
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这swap被称为?而在另一种情况下,为什么swap没有const …
例如:
#include<vector>
using namespace std;
int main()
{
vector<int[]> vec;//serious compiler error
vector<int[2]> vec={{1,2}};//error:array must be initialized with a brace-enclosed initializer
}
Run Code Online (Sandbox Code Playgroud)
另外,如何纠正第二个语法?我已经使用了大括号括起来的初始化器.
据我所知,URL编码的存在是因为URL只支持ASCII编码。但既然"已经在 ASCII 表中了,为什么还要像%22URL 编码那样进行编码呢?