嗨,我想了解为什么以下代码使用正则表达式进行拆分字符串拆分
#include<regex>
#include<vector>
#include<string>
std::vector<std::string> split(const std::string &s){
static const std::regex rsplit(" +");
auto rit = std::sregex_token_iterator(s.begin(), s.end(), rsplit, -1);
auto rend = std::sregex_token_iterator();
auto res = std::vector<std::string>(rit, rend);
return res;
}
int main(){
for(auto i=0; i< 10000; ++i)
split("a b c", " ");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
比下面的python代码慢
import re
for i in range(10000):
re.split(' +', 'a b c')
Run Code Online (Sandbox Code Playgroud)
这里的
> python test.py 0.05s user 0.01s system 94% cpu 0.070 total
./test 0.26s user 0.00s system 99% cpu 0.296 total …Run Code Online (Sandbox Code Playgroud) 有谁知道以下隐含的'ts'捕获是否格式正确:
template<class ... Ts> void bar(Ts ... ts) { }
template<class ... Ts> int foo(Ts ... ts) {
auto L = [=] () {
bar(ts...);
};
L();
return 0;
}
int g = foo(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
标准是否清楚地说明了这个不应该很好的形成?
假设有一个以某种方式存储的参数列表,例如,在数组中.
给定一个函数指针,我如何调用它来传递存储的参数列表?
我不是试图将数组作为参数传递好.你明白了,好吗?我想将每个元素作为参数传递.一个数组只是为了说明,我可以将参数存储在一些元组结构中.另外,看看我手头有一个函数指针,并且可能有字符串格式的签名.我不是只想定义一个能够处理可变列表的函数.
我看到如何做到这一点的唯一方法是使用汇编(由__asm push等人)或这个:
void (*f)(...);
int main()
{
f = <some function pointer>;
int args[]; <stored in a array, just to illustrate>
int num_args = <some value>;
switch(num_args)
{
case 0:
f();
break;
case 1:
f(args[0]);
break;
case 2:
f(args[0], args[1]);
break;
/* etc */
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我不太喜欢这种做法......
还有另一种便携式和更短的形式吗?
有几种脚本语言可以调用C函数.
像Python或Ruby这样的脚本语言是如何做到的?他们如何以便携方式实现它?他们最近只是为几个平台或上面的平台使用组件吗?
看看我真的不是在询问参数封送的细节以及从脚本语言到C的其他内容,我只对内部如何构建脚本语言对C函数的调用感兴趣.
我将保留问题的标题,但我认为更好的方式是:
如何调用C函数,其指针和签名仅在运行时可用?
来自外国接口的PLT计划:
呼出是正常的函数调用.在动态设置中,我们创建一个"调用接口"对象,它指定(二进制)输入/输出类型; 此对象可以与任意函数指针和输入值数组一起使用,以执行函数的调用并检索其结果.这样做需要操纵堆栈并知道如何调用函数,这些是libffi处理的细节.
感谢@AnttiHaapala搜索,查找和指向libffi.这就是我所寻找的,它被一堆脚本语言所使用,它是一个可移植的库,在多个架构和编译器中实现.
最近我发现 ,有时能够将rvalues 暂时变成左值对我来说很有用.
我一直在使用以下工具:
#include <type_traits>
template <typename T>
inline constexpr std::remove_reference_t<T> &lvalue(T &&r) noexcept {
return static_cast<std::remove_reference_t<T> &>(r);
}
Run Code Online (Sandbox Code Playgroud)
当您必须使用需要左值作为参数的函数时,它很有用,但您对这些特定值的变化没有任何兴趣.当您对与给定的特定参数无关的其他输出向量感兴趣时.
例如,这个:
std::string get_my_file() {
std::ifstream ifs("myfile.txt");
return {std::istreambuf_iterator<char>(ifs), {}};
}
Run Code Online (Sandbox Code Playgroud)
可以改为:
std::string get_my_file() {
return {std::istreambuf_iterator<char>(lvalue(std::ifstream("myfile.txt"))),
{}};
}
Run Code Online (Sandbox Code Playgroud)
还有这个:
std::string temp1 = get_my_shader();
const char *temp2 = temp1.c_str();
glShaderSource(a, 1, &temp2, nullptr);
Run Code Online (Sandbox Code Playgroud)
可以改为:
glShaderSource(a, 1, &lvalue(get_my_shader().c_str()), nullptr);
Run Code Online (Sandbox Code Playgroud)
并允许这样的事情:
void foo(int *x) {
std::cout << *x << std::endl;
}
foo(&lvalue(5));
Run Code Online (Sandbox Code Playgroud)
我想确定我是否在调用任何未定义的行为,因为我没有看到任何行为,尽管可能会有一些转换规则将其视为非法(我忽略).关于临时的生命,我没有看到问题,因为AFAIK,rvalues直到完全表达结束并且函数的使用仅限于此.
有一个最近约标准的变化reinterpret_cast和xvalues …
这篇文章讨论了一个名为"零度规则"的成语.
这是一段摘录:
class module {
public:
explicit module(std::wstring const& name)
: handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}
// other module related functions go here
private:
using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
module_handle handle;
};
Run Code Online (Sandbox Code Playgroud)
它重用了unique_ptrRAII功能,因此您无需关心实现令人生畏和冗长的Rule of Five包装器.
以这种方式呈现(以这种方式管理基于句柄的资源unique_ptr),它看起来像是一个黑客,而不是它试图解决的最佳解决方案.隐含地假设了太多的假设:
#define(或typedef)HANDLE构建的基本类型.对我来说,这应该是隐藏的知识,而解决方案完全基于界面提供的内容:HANDLE.我想用这个成语,但在我偶然发现的许多情况下都不尽如人意.
这个手柄是否集中了RAII包装器已经完成并可以在一些很酷的库中使用?每个人都使用这样的工具,我不知道吗?(我觉得很高兴有这样的工具不仅适用于一个,而且适用于许多类型的所有权)
这不是关于平台特定的资源句柄,例如,glGenLists返回一种句柄,它是一个GLuint,你应该调用glDeleteLists它.如前所述,资源句柄不需要是指针类型,不应假设这种假设.
在前一个示例中,使用现有工具的Zero of Zero unique_ptr显示为句柄管理的一个很好的捷径.它所需的额外假设使其不足.正确的假设是你有一个句柄,你有一个资源破坏功能,破坏句柄给出的资源.无论句柄是a void …
2013年主题演讲:Chandler Carruth:优化C++的紧急结构
任何人都可以把这个放在这个答案的上下文中:https://stackoverflow.com/a/14229152
我听说不断重复,但是,对我而言,返回某些东西的功能是一个来源.通过引用的输出参数从功能中获取该特性,并且从功能中移除这种硬编码特性允许人们在外部管理,输出将如何被存储/重用.
我的问题是,即使在SO答案的上下文中,也有一种方法可以告诉,重构代码还有一些其他等效方式,"好了,现在看看,这种方式的值语义不会因输出参数版本而丢失",或者钱德勒的评论是针对一些人为的情况而定的?我甚至看过Andrei Alexandrescu在一次演讲中争论这个并且告诉你无法通过ref输出来逃避使用以获得更好的性能.
关于Andrei评论的另一个观点,请参阅Eric Niebler:Out Parameters,Move Semantics和Stateful Algorithms.
12.6.1 - 显式初始化
struct complex {
complex();
complex(double);
complex(double,double);
};
complex sqrt(complex,complex);
complex g = { 1, 2 }; // construct complex(1, 2)
// using complex(double, double)
// and *copy/move* it into g
Run Code Online (Sandbox Code Playgroud)
8.5初始化器
14 - 表单中发生的初始化
T x = a;以及参数传递,函数返回,抛出异常(15.1),处理异常(15.3)和聚合成员初始化(8.5.1)称为复制初始化.[注意:复制初始化可以调用移动(12.8). - 结束说明]
15 - 表单中发生的初始化
T x(a);
T x{a};以及在新表达式(5.3.4)中,static_cast表达式(5.2.9),函数表示法类型转换(5.2.3)以及基本和成员初始化器(12.6.2)称为直接初始化.
8.5.4列表初始化[dcl.init.list]
1 - 列表初始化是从braced-init-list初始化对象或引用.这样的初始化程序称为初始化程序列表,列表的逗号分隔的初始化程序子句称为初始化程序列表的元素.初始化列表可以为空.列表初始化可以在直接初始化或复制初始化上下文中进行; 列表中的初始化 直接初始化上下文被称为在直接列表初始化和列表初始化拷贝初始化上下文被称为副本列表初始化.
29.6.5对原子类型的操作要求[atomics.types.operations.req]
#define ATOMIC_VAR_INIT(value)见下文宏扩展为适合于初始化与值一致的类型的静态存储持续时间的原子变量的常量初始化的令牌序列.[注意:此操作可能需要初始化锁. - 结束注释]即使通过原子操作,对正在初始化的变量的并发访问构成了数据竞争.[例如:
atomic<int> v = ATOMIC_VAR_INIT(5);
根据前面的部分,似乎不应该在没有复制构造函数的情况下进行赋值初始化,即使它根据§12.8.31和§12.8.32被省略,但是原子被定义为:
29.5原子类型[atomics.types.generic]
atomic() …Run Code Online (Sandbox Code Playgroud) C++的STL优先级队列有一个void pop()方法和一个const ref top()方法.因此,如果要将元素移出队列,则必须执行以下操作:
T moved = std::move(const_cast<T&>(myQueue.top())));
myQeue.pop();
Run Code Online (Sandbox Code Playgroud)
这有效地将顶部强制转换为常量,以便可以移动(而不是复制).我不喜欢这段代码,因为强制移动可能会使优先级队列的不变量无效,这不应该因为pop而烦恼,但事情可能会出错.
有没有更好的方法来完成弹出/移动?为什么没有T && top_and_pop()函数?
一位博客作者提出了有关空指针解除引用的讨论:
我在这里提出一些反驳论点:
他引用标准的主要推理理由是:
当'podhd'是空指针时,'&podhd-> line6'表达式在C语言中是未定义的行为.
C99标准说明了以下关于'&'地址的运算符(6.5.3.2"地址和间接运算符"):
一元&运算符的操作数应该是函数指示符,[]或一元*运算符的结果,或者是一个左值,它指定一个不是位字段的对象,并且不用寄存器存储类说明符声明.
表达式'podhd-> line6'显然不是函数指示符,是[]或*运算符的结果.这是一个左值表达式.但是,当'podhd'指针为NULL时,表达式不指定对象,因为6.3.2.3"Pointers"表示:
如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.
当"左值在评估时未指定对象时,行为未定义"(C99 6.3.2.1"左值,数组和函数指示符"):
左值是具有对象类型或除void之外的不完整类型的表达式; 如果左值在评估时未指定对象,则行为未定义.
所以,同样的想法简要说明:
当在指针上执行 - >时,它会计算到没有对象存在的左值,因此行为是未定义的.
这个问题纯粹是基于语言的,我不会问一个给定的系统是否允许用任何语言篡改地址0的内容.
据我所知,取消引用一个值等于的指针变量没有限制nullptr,甚至认为指针与nullptr(或(void *) 0)常量的比较在某些情况下可能会因为所述段落而在优化中消失,但这看起来像另一个问题是,它不会阻止取消引用其值等于的指针nullptr.请注意,我已经检查了其他SO问题和答案,我特别喜欢这组引用,以及上面的标准引号,我没有偶然发现一些明显从标准中推断出如果指针ptr比较等于nullptr,取消引用这将是未定义的行为.
我得到的最多是将常量(或其转换为任何指针类型)引用的是UB,但没有任何关于变量等于从中得到的值的变量nullptr.
我想清楚地将nullptr常量与保持值等于它的指针变量分开.但解决这两种情况的答案都是理想的.
我确实意识到,当进行比较nullptr等时,优化可以快速进行,并且可以简单地基于此来剥离代码.
如果结论是,如果ptr等于nullptr解除引用的值肯定是UB,另一个问题如下:
在OS X上,在任何程序中,当我输入option-p我得到?,option-P我得到?并有一堆alt/ option绑定刚刚返回希腊和其他特殊字符.
有没有办法禁用它?
目前我正在使用Auto Pairs VIM插件,它具有以下默认映射:
<M-p> : Toggle Autopairs (g:AutoPairsShortcutToggle)
<M-e> : Fast Wrap (g:AutoPairsShortcutFastWrap)
<M-n> : Jump to next closed pair (g:AutoPairsShortcutJump)
<M-b> : BackInsert (g:AutoPairsShortcutBackInsert)
Run Code Online (Sandbox Code Playgroud)
在启用此特殊输入时,似乎无法使用这些和其他基于元键的VIM映射.
编辑
从这篇cnet文章中,实际上我需要知道如何禁用页面底部显示的特殊输入.