这个故事与我之前的问题类似.支持C++ 11的所有GCC版本都具有这种确切的行为.我找不到任何其他编译器与我的测试用例斗争.
测试用例:
struct BaseFooWrapper
{
BaseFooWrapper(int qux)
{ }
};
struct Foo
{
Foo(BaseFooWrapper & foo)
: foo(foo)
{ }
BaseFooWrapper & foo;
};
struct SomeFooWrapper : public BaseFooWrapper
{
using BaseFooWrapper::BaseFooWrapper;
Foo foo{*this};
};
int main()
{
SomeFooWrapper wrapped_foo(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码用clang(3.4到4.0),icc(16,17),Visual C++(19.00.23506)编译.
如果我用手写版本替换构造函数继承,那么GCC开始编译代码:
struct BaseFooWrapper
{
BaseFooWrapper(int qux)
{ }
};
struct Foo
{
Foo(BaseFooWrapper & foo)
: foo(foo)
{ }
BaseFooWrapper …Run Code Online (Sandbox Code Playgroud) 考虑简单的代码片段
#include <map>
#include <string>
struct Foo
{
Foo(const std::map<std::string, int> & bar = std::map<std::string, int>())
:bar(bar)
{ }
std::map<std::string, int> bar;
};
int main(int argc, char ** argv)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我像这样编译它时:clang++ -o foo foo.cpp我遇到错误:
foo.cpp:7:73: error: expected ')'
Foo(const std::map<std::string, int> bar = std::map<std::string, int>())
^
foo.cpp:7:8: note: to match this '('
Foo(const std::map<std::string, int> bar = std::map<std::string, int>())
^
foo.cpp:7:68: error: expected '>'
Foo(const std::map<std::string, int> bar = std::map<std::string, int>())
^
Run Code Online (Sandbox Code Playgroud)
clang 3.2和 …
为什么这个功能看起来如此有争议?我看到它没有与其他概念TS一起合并到C++ 20中.通过网络搜索,除了可以应用于几乎任何新的C++特性的通用参数之外,我找不到合理的参数.
人们如此害怕什么?那里有什么陷阱?毕竟,我们已经有了通用的lambda.
关于标准如何管理这种情况,我有点困惑:
struct Foo {
Foo & operator = (std::string xxx)
{
x = std::move(xxx);
return *this;
}
std::string x;
};
std::map<std::string, Foo> bar;
std::string baz = "some string";
bar[baz] = std::move(baz);
Run Code Online (Sandbox Code Playgroud)
编译器是否可以生成代码,以便在用于初始化和引用元素(初始化)之前baz移动代码?或者这段代码是否安全且没有未定义的行为?barstd::string xxx
我怀疑这accumulate不是唯一没有成功的算法。
也许现在有更好的方法来在一个范围内执行累积(折叠),因此accumulate已经过时了?
这更像是一种哲学类型的问题.
在C++中,我们有很好的闪亮成语 - RAII.但我常常认为它不完整.它与我的应用程序可以用SIGSEGV杀死的事实不太一致.
我知道,我知道,像你这样的程序是不正确的.但令人遗憾的是,在POSIX(特别是Linux)上,您可以分配超出物理内存限制并在执行过程中满足SIGSEGV,使用正确分配的内存.
你可能会说:"应用程序死了,你为什么要关心那些没有被调用的糟糕的析构函数?".遗憾的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体.
我现在非常厌倦了设计黑客,破坏良好的应用程序设计以应对这一点.所以,我要问的是为这类问题提供一个漂亮,优雅的解决方案.
似乎我错了,Linux应用程序被内核寻呼机杀死.在这种情况下,问题仍然是相同的,但申请死亡的原因是不同的.
代码段:
struct UnlinkGuard
{
UnlinkGuard(const std::string path_to_file)
: _path_to_file(path_to_file)
{ }
~UnlinkGuard() {
unlink();
}
bool unlink() {
if (_path_to_file.empty())
return true;
if (::unlink(_path_to_file.c_str())) {
/// Probably some logging.
return false;
}
disengage();
return true;
}
void disengage() {
_path_to_file.clear();
}
private:
std::string _path_to_file;
};
void foo()
{
/// Pick path to temp file.
std::string path_to_temp_file = "...";
/// …Run Code Online (Sandbox Code Playgroud) 我非常支持制作std::shared_ptr<T>接受T *显式的构造函数的想法.当你正在查看堆损坏的原因时,它有助于挽救不眠之夜.Scott Meyers对此给出了很好的解释.
但是......如果我给它一个rvalue指针不明白吗?我可以这样做:
/// (1)
std::shared_ptr<T> t = new T;
Run Code Online (Sandbox Code Playgroud)
要么
/// (2)
T * giveaway = new T;
std::shared_ptr<T> t = std::move(giveaway);
Run Code Online (Sandbox Code Playgroud)
或者是现实生活中更痛苦的一个案例
/// (3)
void foo(std::shared_ptr<T> t);
/// ...
foo(new T);
Run Code Online (Sandbox Code Playgroud)
至于我,所有这些案例都足够明确.
情况(1)是一个prvalue,我不可能搞砸两个指针.至少不过是使用:
std::shared_ptr<T> t{new T};
Run Code Online (Sandbox Code Playgroud)
案例(2)非常明确.一致同意,在你移动了某些东西后,它的值变得不确定.所以使用它完全取决于你.
案例(3)rvalue再次出现.
(Q1)这是标准委员会的俯视吗?
(Q2)有这个原因吗?
(Q3)隐式构造函数是否有机会接受rvalue在C++ 14中出现?
在互联网上挖掘了几个小时,我找不到我的问题的答案。
我的模型是这样的:我有一个boost::asio::ssl::context用于创建实例的共享boost::asio::ssl::stream. 然后流对象被传递到不同的线程。
这个模型线程安全吗?是否可以boost::asio::ssl::context在构建将同时使用的不同 SSL 流对象时使用相同的内容?
请在将此问题标记为重复之前,仔细阅读说明。谢谢!
我的具体情况是,线程之间没有共享对象。所以Boost.Asio SSL 线程安全 线程安全中所说的任何内容都不会影响我的情况。我boost::asio::ssl::context从单个线程访问。
具体来说:直接列表初始化(cppreference.com (3)).
C++ 11中引入了两者std::make_shared和统一初始化功能.所以我们可以在堆上分配对象时使用聚合初始化:.这是直接初始化没有构造函数的对象的好方法,例如聚合,pod等.new Foo{1, "2", 3.0f}
根据我的经验,现实生活场景,例如在函数中声明临时结构,有效地为lambda提供一组参数变得非常普遍:
void foo()
{
struct LambdaArgs
{
std::string arg1;
std::string arg2;
std::string arg3;
};
auto args = std::make_shared<LambdaArgs>(LambdaArgs{"1", "2", "3"});
auto lambda = [args] {
/// ...
};
/// Use lambda
/// ...
}
Run Code Online (Sandbox Code Playgroud)
这里auto args = std::make_shared<LambdaArgs>("1", "2", "3");应该很好但不会起作用,因为std::make_shared通常实现为:
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args && ...args)
{
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)
所以我们坚持了auto …
我的类中有一个成员函数_wrapper,它封装了一些围绕其他函数族的常见逻辑.此包装函数接受指向正在包装的函数及其参数的指针.
我的类中的包装器实现类似于在此示例类中完成的方式Foo:
#include <functional>
class Foo
{
public:
void bar1(int a)
{
/// No-op.
}
void bar1(int a, int b)
{
/// No-op.
}
void bar2(const int & a)
{
/// No-op.
}
void foo(int x)
{
_wrapper_bar1(x); /// No problems to deduce type
_wrapper_bar2(x); /// No problems to deduce type
_wrapper(&Foo::bar1, x); /// Deduction fails
_wrapper(&Foo::bar2, x); /// Deduction fails
}
private:
template <typename ...Args>
void _wrapper(void (Foo::*method) (Args ...), Args && ...args)
{
/// …Run Code Online (Sandbox Code Playgroud) 在32位平台上的libc ++中,int64_t被定义为别名long long.在64位平台上:long.
另一方面,在std::chrono::duration别名的定义中,您可以在这里 long long不经意地使用:
typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long > seconds;
typedef duration< long, ratio< 60> > minutes;
typedef duration< long, ratio<3600> > hours;
Run Code Online (Sandbox Code Playgroud)
因此,例如,当我需要严格8字节长的类型时,我会期望
foo(uint64_t);
foo(int64_t);
Run Code Online (Sandbox Code Playgroud)
是一个相当便携的解决方案.但是在libc ++的情况下,chrono它不是真的.除了编写类似于你自己的逻辑之外,没有可移植的方法<cstdint>.即,定义的两个额外的定义,foo称取long long和unsigned long long.
或者另一个例子:
foo(int8_t);
foo(int16_t);
foo(int32_t);
foo(int64_t);
Run Code Online (Sandbox Code Playgroud)
foo(duration.count())在这种情况下,呼叫将是模棱两可的.
那么什么用的点long long是不大于long但它的等级大于 …