我最初发布这个只是关于析构函数的问题,但现在我正在添加对默认构造函数的考虑.这是原始问题:
如果我想给我的类一个虚拟的析构函数,但是与编译器生成的析构函数相同,我可以使用
=default:Run Code Online (Sandbox Code Playgroud)class Widget { public: virtual ~Widget() = default; };但似乎我可以通过使用空定义减少输入来获得相同的效果:
Run Code Online (Sandbox Code Playgroud)class Widget { public: virtual ~Widget() {} };这两种定义的行为方式有何不同?
根据此问题的回复,默认构造函数的情况似乎相似.鉴于析构函数的" =default"和" {}"之间的含义几乎没有差异,默认构造函数的这些选项之间的含义几乎没有差别吗?也就是说,假设我想创建一个类型,其中该类型的对象将被创建和销毁,为什么我要说
Widget() = default;
Run Code Online (Sandbox Code Playgroud)
代替
Widget() {}
Run Code Online (Sandbox Code Playgroud)
?
如果在原始帖子违反某些SO规则后延长此问题,我深表歉意.为默认构造函数发布一个几乎完全相同的问题让我觉得不太理想.
c++ user-defined-functions default-constructor deleted-functions c++11
C++ 98有front_inserter,back_inserter和inserter,但在C++ 11或草案C++ 14中似乎没有任何这些版本.有没有我们不能有任何技术原因front_emplacer,back_emplacer和emplacer?
草案C++ 14包括运行时大小的数组和std::dynarray容器.从我所知道的,两者之间的唯一真正的区别在于std::dynarray有一个STL接口(例如begin,end,size,等),同时运行时大小的数组没有.那么为什么C++ 14需要它们呢?
我知道运行时大小的数组是核心语言的std::dynarray一部分,同时也是标准库的一部分,但是该提议std::dynarray清楚地表明作者希望编译器在许多情况下能够提供特殊支持,std::dynarray以便它可以高效尽可能地,即,与运行时大小的数组一样高效.因此,语言/库的区别似乎有点人为.
那么,为什么C++ 14需要两个运行时大小的数组std::dynarray呢?并且鉴于它std::dynarray具有更丰富的(STLified)接口,为什么不只是删除运行时大小的数组,假设std::dynarray可以以相同的运行时效率实现?
澄清
当我谈到"运行时大小的数组"时,我指的是N3639中描述的新的C++ 14核心语言特性,而不是传统的C数组或VLA或C++ 11中的任何内容.
我注意到std::string(真的std::basic_string是)移动赋值运算符是 noexcept.这对我来说很有意义.但后来我发现,没有一个标准集装箱(例如std::vector,std::deque,std::list,std::map)宣布其移动赋值操作符noexcept.这对我来说没什么意义.std::vector例如,A 通常实现为三个指针,并且指针当然可以移动分配而不会抛出异常.然后我想也许问题是移动容器的分配器,但std::string也有分配器,所以如果这是问题,我希望它会影响std::string.
那么为什么std::string移动赋值运算符noexcept,但标准容器的移动赋值运算符不是?
使用std::async而不是手动创建std::thread对象的优点之一应该是std::async可以使用封面下的线程池来避免超额配置问题.但是哪些实现这样做?我的理解是微软的实现确实如此,但这些其他async实现呢?
boost::thread::async,不std::async)感谢您提供的任何信息.
假设我有一个类,其唯一目的是在构造对象时产生的副作用(例如,使用工厂注册类):
class SideEffectCauser {
public:
SideEffectCauser() { /* code causing side-effects */ }
};
Run Code Online (Sandbox Code Playgroud)
还假设我想让一个对象为每个翻译单元创建一次这样的副作用.对于每个这样的翻译单元,我希望能够SideEffectCauser在.cpp文件中的命名空间范围内放置一个对象,例如,
SideEffectCauser dummyGlobal;
Run Code Online (Sandbox Code Playgroud)
但C++标准03 3.6.2/3表明,此对象不必在所有的构造,除非使用在.cpp文件中的对象或功能,如文章这和网上的讨论,如这表明,这种对象有时不会被初始化.
另一方面,有没有办法从持有类名的字符串中实例化对象?有一个声称工作的解决方案,我注意到它基于使用类型的对象,SideEffectCauser如静态数据成员,而不是全局,例如,
class Holder {
static SideEffectHolder dummyInClass;
};
SideEffectHolder Holder::dummyInClass;
Run Code Online (Sandbox Code Playgroud)
两个dummyGlobal和dummyInClass是非本地静态的,但在C++ 03标准的3.6.2/3细看表明,该通道仅适用于对象在命名空间范围.我实际上无法在C++ 03标准中找到任何内容,即当类范围内的非局部静态动态被动态初始化时,尽管9.4.2/7表明相同的规则适用于它们与命名空间中的非局部静态范围.
问题1:在C++ 03中,有没有理由相信它dummyInClass更有可能被初始化dummyGlobal?或者,如果同一翻译单元中没有使用任何功能或对象,可能都会未初始化?
问题2:C++ 11中有什么变化吗?3.6.2和9.4.2中的措辞与C++ 03版本不同,但据我所知,上面描述的场景没有指定行为差异.
问题3:是否有一种可靠的方法来使用类SideEffectHolder功能体外的类对象来强制发生副作用?
这是有效的代码:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
const int xVal { 0 };
const int yVal { 0 };
};
Run Code Online (Sandbox Code Playgroud)
但在这里我真的想申报xVal并 - 像yVal constexpr这样:
struct S {
constexpr S(int x, int y): xVal(x), yVal(y) {}
constexpr S(int x): xVal(x) {}
constexpr S() {}
constexpr int xVal { 0 }; // error!
constexpr int yVal { 0 }; // error!
};
Run Code Online (Sandbox Code Playgroud)
如上所示,代码将无法编译.原因是(根据7.1.5/1),只能声明静态数据成员constexpr.但 …
C++ 11使得基于引用限定符重载成员函数成为可能:
class Foo {
public:
void f() &; // for when *this is an lvalue
void f() &&; // for when *this is an rvalue
};
Foo obj;
obj.f(); // calls lvalue overload
std::move(obj).f(); // calls rvalue overload
Run Code Online (Sandbox Code Playgroud)
我理解这是如何工作的,但它的用例是什么?
我看到N2819建议将标准库中的大多数赋值运算符限制为左值目标(即向赋值运算符添加" &"引用限定符),但这被拒绝了.所以这是一个潜在的用例,委员会决定不再使用它.那么,再一次,什么是合理的用例?
这个问题是基于Scott Meyers最近发表的博客文章.
看起来"显而易见" std::swap(x, x)应该x在C++ 98和C++ 11中保持不变,但我无法在任何标准中找到任何保证.C++ 98 std::swap在复制构造和复制赋值方面进行了定义,而C++ 11则根据移动构造和移动赋值来定义它,这似乎是相关的,因为在C++ 11(和C++ 14)中,17.6 .4.9表示移动分配不需要自我分配安全:
如果函数参数绑定到右值引用参数,则实现可以假定此参数是对此参数的唯一引用.... [注意:如果程序在将左值传递给库函数时将左值转换为x值(例如通过使用参数move(x)调用函数),程序实际上要求该函数将该左值视为暂时的.实现可以自由地优化别名检查,如果参数是左值,则可能需要这些检查. - 尾注]
引起这种措辞的缺陷报告使结果清晰:
这澄清了移动赋值运算符不需要执行复制赋值运算符中常见(并且需要)的传统if(this!=&rhs)测试.
但是在C++ 11和C++ 14中,std::swap预计会使用这个实现,
template<typename T>
void swap(T& lhs, T& rhs)
{
auto temp(std::move(lhs));
lhs = std::move(rhs);
rhs = std::move(temp);
}
Run Code Online (Sandbox Code Playgroud)
并且第一个赋值是对self进行赋值,其中参数是rvalue.如果移动赋值运算符T遵循标准库的策略并且不担心赋值给自己,那么这似乎可以判断未定义的行为,这也意味着它std::swap(x, x)也会具有UB.
即使是孤立的,这也是令人担忧的,但是如果我们认为std::swap(x, x)在C++ 98中应该是安全的,那么这也意味着C++ std::swap11/14可以默默地破坏C++ 98代码.
所以std::swap(x, x)保证x保持不变?在C++ 98中?在C++ 11中?如果是,那么它如何与17.6.4.9的移动分配许可相互作用而不是自我分配安全的?
如果我有一个int,将其转换为一个double,然后转换double回的int,我保证可以得到相同的值返回,我开始?换句话说,给定此功能:
int passThroughDouble(int input)
{
double d = input;
return d;
}
Run Code Online (Sandbox Code Playgroud)
我能保证passThroughDouble(x) == x所有int的x吗?