一个小时前我在这里发了一个答案,根据我的说法是正确的.然而我的回答却被Martin B贬低了.他说
你很幸运,并且因为我所处的内存恰好是零初始化而得到了零.标准不保证这一点.
然而读迈克尔·伯尔的回答后,这里并尝试下面的示例代码
1)
#include <cassert>
struct B { ~B(); int m; };
int main()
{
B * b = new B();
assert(b->m == 0);
}
Run Code Online (Sandbox Code Playgroud)
我在MSVC++ 2010上遇到调试错误.
我有一个类似的错误,当我尝试下面的代码[我的答案在这里 ]在MSVC++ 2010
2)
#include <cassert>
struct Struct {
std::string String;
int Int;
bool k;
// add add add
};
struct InStruct : Struct
{
InStruct() : Struct() {}
};
int main()
{
InStruct i;
assert(i.k == 0);
}
Run Code Online (Sandbox Code Playgroud)
既没有(1)
也没有(2)
给gcc/Clang这样的错误让我想到MSVC++ …
我有以下功能:
... getX()
{
static int x[] = {1, 2, 3};
return x;
}
Run Code Online (Sandbox Code Playgroud)
我想要它的返回类型,int(&)[3]
但不要明确指定大小(3).
我怎么做?
(请不要问我为什么要那样.)
UPD
嗯,好的,我需要将结果传递给模板函数int(&x)[N]
作为参数(我不想将大小明确地传递给该模板函数),所以我看不到返回一对的解决方案如何工作...
关于 Python 协程(我主要是指async/await
)是无堆栈的还是有堆栈的,我看到了相互矛盾的观点。
一些消息来源称它们是堆栈的:
“Python 协程是堆栈式的。”
是的,Python 协程是堆栈式的、一流的且不对称的。
虽然其他人似乎暗示它们是无堆栈的,例如https://gamelisp.rs/reference/coroutines.html
GameLisp 的协程遵循 Rust、Python、C# 和 C++ 设置的模型。我们的协程是“无堆栈的”
总的来说,我的理解始终是,任何有意义的 async/await 实现都意味着无堆栈协程,而堆栈协程基本上是纤程(用户空间线程,通常或多或少地协作切换),例如 goroutine、Boost.Coroutine,显然是 Lua 中的协程等。
我的理解正确吗?或者 Python 协程在某种程度上与 C++ 中的协程有根本的不同,并且是堆栈式的?或者上述来源的作者是否有不同的意思?
template <typename T> struct A {
A(T);
A(const A&);
};
int main()
{
A x(42); // #1
A y = x; // #2
}
Run Code Online (Sandbox Code Playgroud)
据我了解,T
#1将使用第一个ctor生成的隐式演绎指南推导出.然后x
将使用该ctor初始化.
但是对于#2,T
将使用复制演绎候选人推断(根据我的理解,这是演绎指南的特定情况)(然后y
将使用第二个ctor初始化).
为什么不能T
使用复制版本生成的(隐含)演绎指南来推导#2?
我想我只是不明白复制演绎候选人的一般目的.
c++ templates template-argument-deduction argument-deduction c++17
例如,我想我理解直接初始化(vs copy-)的上下文中的列表初始化 - 基本上是int x{}
vs.int x = {}
但是在cppreference上我发现了这个:
当类类型的对象从相同或派生类类型的对象进行复制初始化,或者在复制初始化上下文中进行默认初始化时,候选函数都是转换正在初始化的类的构造函数.参数列表是初始化程序的表达式.
我想我明白为什么候选人为第一种情况转换构造函数,但不是第二种情况.我的意思是,我不能写出类似的内容MyClass x = MyClass
,并且= MyClass()
会进行值初始化,并且= MyClass(args...)
会直接启动.
即使存在这样的构造,我也不明白为什么临时MyClass
对象'构造'应该特别包括所有转换构造函数.
(x
正如我所看到的那样,并不是在这里讨论的东西,因为它绝对是复制构造的,而不是默认构造的.)
所以我想我对这里的条款感到困惑.
我对这个问题的广泛性感到抱歉,只是所有这些细节都是紧密相连的。
我一直在尝试理解两个特定值类别 - xvalues 和 prvalues 之间的区别,但我仍然感到困惑。
不管怎样,我试图为自己开发的“同一性”概念的心智模型是,应该保证具有同一性的表达式驻留在实际程序的数据存储器中。
由于这个原因,字符串文字是左值,它们保证在整个程序运行期间驻留在内存中,而数字文字是纯右值,并且可以假设存储在直接汇编中。
这似乎同样适用于std::move
纯纯右值文字,即,在调用时,fun(1)
我们只会在被调用者框架中获得参数左值,但在调用时,fun(std::move(1))
左值的 xvalue“种类”必须保留在调用者框架中。
然而,这种心理模型至少不适用于临时对象,据我所知,临时对象应该始终在实际内存中创建(例如,如果像使用纯右值参数那样调用fun(MyClass())
右值引用函数)。所以我认为这种思维模式是错误的。
那么,思考 xvalue 的“同一性”属性的正确方法是什么?我已经读过,通过身份我可以比较地址,但是如果我可以比较 2 的地址MyClass().member
(根据 cppreference 的 xvalue),比方说通过右值引用将它们传递到某个比较函数中,那么我不明白为什么我可以不对 2 MyClass()
s(纯右值)做同样的事情吗?
与此相关的另一个来源是此处的答案: 什么是移动语义?
请注意,尽管 std::move(a) 是右值,但其求值不会创建临时对象。这个难题迫使委员会引入第三个价值类别。可以绑定到右值引用的东西,即使它不是传统意义上的右值,也称为xvalue(到期值)。
但这似乎与“可以比较地址”无关,并且a)我不明白这与右值的“传统意义上”有什么不同;b) 我不明白为什么这样的原因需要语言中的新值类别(好吧,这允许为 OO 意义上的对象提供动态类型,但 xvalue 不仅仅指对象)。
考虑不涉及复制省略的情况(前C++ 17).
从cppreference(再次假设C++ 14):
在以下情况下创建临时对象:
- 绑定对prvalue的引用
- 从函数返回一个prvalue
- 转换,创建一个prvalue
- lambda表达式
- 需要转换初始化程序的复制初始化
- list-initialization,用于构造std :: initializer_list
- 引用初始化为不同但可转换的类型或位域.
除了第一个案例之外的所有案例似乎都无关紧要,第一个案例似乎意味着C++风格的引用绑定(int &&x = 5;
BTW我不明白在这种情况下临时演员在完整表达结束时被销毁的声明......,对象5指的是在语句结尾处似乎没有被销毁).
因此,据我所知,临时对象的概念仅包括那些保证存储的对象(由于可能的省略,在我的情况下不是这种情况).我对么?或者我在这里误解了什么?
BTW有任何区别MyClass()
,并4
在int x = 4;
(或2 + 2
中int x = 2 + 2;
)?也许我可能是不正确的,第一个是指临时物体,而另外两个不是......
基本上,为什么这是有效的:
auto p1 = new int[10]{5};
但这不是:
auto p1 = new int[10](5);
更一般地说,new-expression初始化程序的规则是什么?
我找到了以下内容:
- 如果省略new-initializer,则默认初始化对象(8.5).[注意:如果未执行初始化,则对象具有不确定的值. - 结束注释] - 否则,根据8.5的初始化规则解释new-initializer以进行直接初始化.
那么第二种情况是无效的,因为smth就像T((5))
是无效的(从表达式直接初始化(5)
)?或者是什么原因?
编辑:好吧,我对(())
事物的建议似乎很愚蠢,因为我认为没有理由为什么只应用于数组new-expression.
实际上,我在网上看到的每个左值到右值转换的例子都与诸如int
等的基本类型有关。
我自己找不到适用于类类型的 l2r 示例;在所有看似适用的例子中,通常有一个函数涉及 lvalue-ref(如 copy-ctor),为此 l2r 似乎被抑制(参见例如这个问题)。
然而,在 l2r 本身的描述中,有一个关于类类型的子句(来自 [conv.lval]):
转换的结果根据以下规则确定:
<...> 如果 T 具有类类型,则转换从泛左值复制初始化 T 类型的临时值,并且转换的结果是临时值的纯右值。
有人可以举一个这个条款的例子吗?我不能。
在以下情况中,inject-class-name被视为类模板本身的模板名称:
- 接下来是<
- 它用作与模板模板参数对应的模板参数
- 它是友元类模板声明的详细类说明符中的最终标识符.
所以我试图检查所有3个案例(另外在基础模糊的背景下,虽然我认为这不应该在这里).
第一种情况似乎很简单.
问题是 - 为什么没有注释出实例?他们不在GCC和Clang上,所以我不认为这是一个实施问题
template <template <class> class> struct A;
template <class T> struct Base {};
template <class T> struct Derived: Base<int>, Base<char>
{
// #1
typename Derived::Base<double> d;
// #2
// using a = A<Base>;
using a = A<Derived::template Base>;
// #3
template<class U1>
friend struct Base;
// template<class U>
// friend struct Derived::template Base;
};
Run Code Online (Sandbox Code Playgroud)
以上规则仅适用于模板本身,而不适用于基础吗?如果是这样,基数的规则是什么,特别是对于最后两个案例?
c++ ×9
c++14 ×6
c++17 ×3
templates ×2
c++11 ×1
coroutine ×1
initializer ×1
overloading ×1
prvalue ×1
python ×1
return-type ×1
template-argument-deduction ×1
temporary ×1
visual-c++ ×1
xvalue ×1