虽然异步IO(带有select/poll/epoll/kqueue等的非阻塞描述符)并不是Web上记录最多的东西,但有一些很好的例子.
但是,所有这些示例在确定了调用返回的句柄后,只有一个do_some_io(fd)"存根".它们并没有真正解释如何在这种方法中最好地接近实际的异步IO.
阻止IO非常整洁,直接读取代码.另一方面,非阻塞,异步IO是毛茸茸的,凌乱的.
有什么办法?什么是健壮和可读的?
void do_some_io(int fd) {
switch(state) {
case STEP1:
... async calls
if(io_would_block)
return;
state = STEP2;
case STEP2:
... more async calls
if(io_would_block)
return;
state = STEP3;
case STEP3:
...
}
}
Run Code Online (Sandbox Code Playgroud)
或者(ab)使用GCC的计算得到的:
#define concatentate(x,y) x##y
#define async_read_xx(var,bytes,line) \
concatentate(jmp,line): \
if(!do_async_read(bytes,&var)) { \
schedule(EPOLLIN); \
jmp_read = &&concatentate(jmp,line); \
return; \
}
// macros for making async code read like sync code
#define async_read(var,bytes) \
async_read_xx(var,bytes,__LINE__)
#define async_resume() \
if(jmp_read) { \
void* …Run Code Online (Sandbox Code Playgroud) 它在[C++ 11:12.8/31]中说明:
复制/移动操作的省略,称为复制省略,允许[...]:
- 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(除函数或catch子句参数之外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
这意味着
#include <iostream>
using namespace std;
struct X
{
X() { }
X(const X& other) { cout << "X(const X& other)" << endl; }
};
X no_rvo(X x) {
cout << "no_rvo" << endl;
return x;
}
int main() {
X x_orig;
X x_copy = no_rvo(x_orig);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将打印
X(const X& other)
no_rvo
X(const X& other)
Run Code Online (Sandbox Code Playgroud)
为什么需要第二个拷贝构造函数?编译器不能简单地延长x的生命周期吗?
我想将文本文件的内容加载到vector<char>(或任何char输入迭代器中,如果可能的话).目前我的代码如下所示:
std::vector<char> vec;
std::ifstream file("test.txt");
assert(file.is_open());
while (!(file.eof() || file.fail())) {
char buffer[100];
file.read(buffer, 100);
vec.insert(vec.end(), buffer, buffer + file.gcount());
}
Run Code Online (Sandbox Code Playgroud)
我不喜欢手动使用缓冲区(为什么100个字符?为什么不是200个,或者25个或者其他什么?),或者这个用了大量的行.代码看起来非常丑陋而且非C++.有更直接的方法吗?
我刚刚写了一个包含一些静态数据成员的类,但现在我收到有关"未定义引用"的错误.为什么这不起作用?我究竟做错了什么?
(注意:这是Stack Overflow的C++常见问题解答的一个条目.如果你想批评在这种形式下提供常见问题解答的想法,那么发布所有这些的元数据的发布将是这样做的地方.这个问题在C++聊天室中受到监控,其中FAQ的想法一开始就出现了,所以你的答案很可能被那些提出想法的人阅读.)
这就是我想做的事情:
ExampleTemplate* pointer_to_template;
cin >> number;
switch (number) {
case 1:
pointer_to_template = new ExampleTemplate<int>();
break;
case 2:
pointer_to_template = new ExampleTemplate<double>();
break;
}
pointer_to_template->doStuff();
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为在声明指针时必须指定模板类型.(ExampleTemplate* pointer_to_template应该是ExampleTemplate<int>* pointer_to_template.)不幸的是,我不知道模板的类型,直到它在switch块中声明.对于这种情况,最好的解决方法是什么?
在基于范围的for循环中声明循环变量是否合法,我在循环的表达式语句中使用了相同的名称?我希望这个例子能说清楚.
#include <iostream>
#include <vector>
struct bar {
std::vector<int> nums;
};
int main()
{
bar b;
b.nums = {1, 2, 3};
for(int b : b.nums)
std::cout << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
当clang 3.2允许时,gcc 4.8给出错误.
我正在使用boost :: program_options从命令行参数中读取用户的输入.它工作得非常好,允许我输出有用的使用信息并正确验证输入.但是,默认情况下,长选项名称必须在双击之后,例如--my_long_option短选项在单个短划线之后,并且必须是单个字符,例如; -m.
还有办法要么......
-?因此允许我拥有看起来像的命令行
./a.out -myopt1 foo -myopt2 bar
Run Code Online (Sandbox Code Playgroud)
这两种可能性应该具有相同的效果,但从编程的角度来看,第一种可能会更好.我看了一下boost :: program_options :: command_line_style,但看起来它看起来不像我需要的那样.
谢谢
编辑:进一步接受下面接受的答案,让它使用该样式必须添加以下代码(遵循提升文档的命名约定)
po::store(
po::command_line_parser(ac,av)
.options(desc)
.style(
po::command_line_style::unix_style
| po::command_line_style::allow_long_disguise)
.run(),
vm);
Run Code Online (Sandbox Code Playgroud) 考虑这个用C++演示RAII的简单类(从我的脑海中开始):
class X {
public:
X() {
fp = fopen("whatever", "r");
if (fp == NULL)
throw some_exception();
}
~X() {
if (fclose(fp) != 0){
// An error. Now what?
}
}
private:
FILE *fp;
X(X const&) = delete;
X(X&&) = delete;
X& operator=(X const&) = delete;
X& operator=(X&&) = delete;
}
Run Code Online (Sandbox Code Playgroud)
我不能在析构函数中抛出异常.我有错误,但无法报告.这个例子非常通用:我不仅可以使用文件,还可以使用例如posix线程,图形资源,...我注意到例如维基百科RAII页面如何扫描地毯下的整个问题:http:// en .wikipedia.org /维基/ Resource_Acquisition_Is_Initialization
在我看来,RAII只有在保证无故障发生的情况下才有用.我知道这个属性的唯一资源是内存.现在在我看来,例如Boehm相当令人信服地揭穿手动内存管理的想法在任何常见情况下都是一个好主意,那么C++使用RAII的方式的优势在哪里呢?
是的,我知道GC在C++世界中有点异端;-)
C中的以下代码是否定义了行为?
int main() {
const int i = 0;
return *(int*)(&i);
}
Run Code Online (Sandbox Code Playgroud)
我问,因为6.5/7列出了"与对象的有效类型兼容的类型的合格版本"作为有效别名.但是对象的有效类型是const int,我认为不是int合格版本const int(尽管反之亦然).既不是int和const int兼容(6.7.3/10).
此外,6.3.2.3/2表示您可以通过添加限定符来转换指针类型,并且结果指针是相等的.6.3.2.3/7表示你可以转换任何两种指针类型(因此(int*)(&i)允许转换本身).但是并没有说结果指针指的是同一个对象,甚至它是相等的.它说的是它可以转换回原始类型(在这种情况下const int*).也就是说,即使别名是合法的,我也不清楚标准是否保证我的指针转换确实会导致指向的指针i.
那么,标准是否实际定义了我的代码的行为,如果是,那么这个定义在哪里?
我知道代码在实践中有效.我想到了一个不起作用的假设(和奇怪)实现.我可以问这个实现是否符合标准(如果不符合,它违反了哪个部分),但如果还有其他方面,我想象的实现无法符合,我不想浑水.如果有人认为这将有助于他们回答问题,我将描述实施.