我刚刚发现basic_string的两个交换函数(命名空间std中的成员函数和函数)没有用noexcept声明- 既不是在GCC-4.8的标准库中也不是在最新的C++草案N3690中.
另一方面,移动构造函数以及移动赋值运算符使用noexcept声明.这表明应该可以提供noexcept交换功能.
问题:没有使用noexcept声明交换函数的原因是什么?
更新:问题是我想在我自己的交换函数中使用模板函数,它使用static_assert检查交换是否实际上是noexcept,例如:
struct foo {
bar_t bar;
baz_t baz;
void swap(foo& rhs) noexcept {
swap_noexcept(bar, rhs.bar);
swap_noexcept(baz, rhs.baz);
}
};
Run Code Online (Sandbox Code Playgroud)
但是,只有在使用noexcept声明交换函数时才有效,但情况并非如此basic_string
.
目前,我试图了解splice/vmsplice的价值.关于IPC的用例,我在stackoverflow上偶然发现了以下答案:https://stackoverflow.com/a/1350550/1305501
问题:如何使用vmsplice将内存页面从一个进程转移到另一个进程而不复制数据(即零拷贝)?
上面提到的答案声称它是可能的.但是,它不包含任何源代码.如果我理解vmsplice
正确的文档,如果内存被正确分配和对齐,以下函数将把内存页面转移到管道(内核缓冲区)而不复制.为了便于演示而省略了错误处理.
// data is aligned to page boundaries,
// and length is a multiple of the page size
void transfer_to_pipe(int pipe_out, char* data, size_t length)
{
size_t offset = 0;
while (offset < length) {
struct iovec iov { data + offset, length - offset };
offset += vmsplice(pipe_out, &iov, 1, SPLICE_F_GIFT);
}
}
Run Code Online (Sandbox Code Playgroud)
但是如何在不复制的情况下从用户空间访问内存页面?显然,以下方法不起作用:
vmsplice
:此功能也可用于反向.但根据内核源代码中的注释,数据将被复制.read
:我可以想象,如果内存正确对齐,这个函数会产生一些魔力,但我对此表示怀疑.mmap
:管道不可能.但是有没有可以使用的某种虚拟文件,即splice
虚拟文件的内存页面mmap
呢?根本不可能vmsplice
吗?
这个问题是关于C++ 11标准库中几个函数的规范,它们将它们的参数作为右值引用,但不要在所有情况下都使用它们.一个例子是
std::unordered_set<T>::insert(T&&)
.
很明显,这个方法将使用移动构造函数T
来构造容器中的元素(如果它尚不存在).但是,如果元素已经存在于容器中会发生什么?我很确定在这种情况下没有理由改变对象.但是,我没有在C++ 11标准中找到支持我的声明的任何内容.
这是一个示例,说明为什么这可能很有趣.以下代码从std :: cin读取行并删除第一次出现的重复行.
std::unordered_set<std::string> seen;
std::string line;
while (getline(std::cin, line)) {
bool inserted = seen.insert(std::move(line)).second;
if (!inserted) {
/* Is it safe to use line here, i.e. can I assume that the
* insert operation hasn't changed the string object, because
* the string already exists, so there is no need to consume it. */
std::cout << line << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
显然,这个例子适用于GCC 4.7.但我不确定,根据标准是否正确.
最近,我跟着讨论了C++中表达式的赋值,如下例所示:
string s1, s2, s3;
(s1 + s2) = s3;
Run Code Online (Sandbox Code Playgroud)
使用C++ 11,可以将赋值运算符限制为左值引用(在左侧).当声明赋值运算符如下时,由于类型不兼容,编译器Clang拒绝带有错误消息的代码.
auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;
Run Code Online (Sandbox Code Playgroud)
我没有在任何地方见过这个.是否有充分的理由不为赋值运算符使用左值引用限定符(除了在大多数编译器中缺少支持)?
我偶然发现了新std::pair
构造函数的一个令人惊讶的行为,这是C++ 11引入的.我在使用时观察到了这个问题std::pair<int, std::atomic<int>>
,并且它发生了,因为std::atomic
它既不可复制也不可移动.在下面的代码,我取代std::atomic<int>
用foobar
了简化.
下面的代码编译很好,包括GCC-4.9和Clang-3.5(有和没有libc ++):
struct foobar
{
foobar(int) { } // implicit conversion
// foobar(const foobar&) = delete;
};
std::pair<int, foobar> p{1, 2};
Run Code Online (Sandbox Code Playgroud)
此行为是预期的.但是,当我删除复制构造函数时foobar
,编译失败.它适用于分段构造,但我认为这不应该是必要的,因为隐式转换int
为foobar
.我指的是具有以下签名的构造函数:
template <typename U, typename V>
pair(U&& u, V&& v);
Run Code Online (Sandbox Code Playgroud)
你能解释为什么对构造函数是如此限制,并且不允许对noncopyable/nonmovable类型进行隐式转换?
我想在一小组机器上支持大约10,000个并发HTTP客户端(尽可能小).我想在用户使用应用程序时保持与每个客户端的连接,以允许服务器推送更新.
我相信通常建议将async IO用于这些长期连接,以避免大量线程处于空闲状态.但线程闲置有什么问题?我发现线程模型在精神上更容易使用,但我不想做一些会让我头疼的事情.我想我将不得不进行实验,但我想知道是否有人知道以前的这些实验中的任何实验?
在java 8中,java.util.stream.Stream#forEach
考虑作为传统for循环的替代.但为什么不是这不是链函数.它返回虚空而不是Stream<T>
自我.
像这样
Arrays
.stream(Girls.toArray())
.forEach(Girls::getUp)
.forEach(Girls::dressUp)
.filter(/* Top 10 Girls */)
.forEach(Gay.getMe()::gotGirl)
.endFilter()// Not an API, but it means remove last filter
.filter(/* Worst 10 Girls */)
.forEach(Gay.get(0)::gotGirl)
girls = Arrays
.stream(Girls.toArray());
girls.forEach(g->{g.getUp();g.dressUp()});
girls.filter(/* Top 10 Girls */)
.forEach(Gay.getMe()::gotGirl);
girls.filter(/* Worst 10 Girls */)
.forEach(Gay.get(0)::gotGirl);
Run Code Online (Sandbox Code Playgroud)
第一个比第二个好.但是第一个表现更差.
那么,为什么forEach
不能连锁?
尝试编译表达式时Comparator.comparing(String::toLowerCase)
,Java编译器返回错误.有关更多信息,请参阅以下问题:
为什么Comparator.comparing不能与String :: toLowerCase方法引用一起使用?
我试图尽可能地减少这个问题.特别是,我已经删除了几乎所有依赖项到其他类.的主要方法包括两个方法调用.第一个语句编译时没有错误,而第二个语句产生错误.
interface Fun<T, R> { R apply(T t); }
public final class Foo {
public static void main(String... args) {
invoke(Foo::bar); // OK
invoke(Foo::baz); // ERROR
}
private static <T, U> void invoke(Fun<T, U> f) { }
private String bar() { return null; }
private String baz() { return null; }
private String baz(Integer i, Integer j) { return null; }
}
Run Code Online (Sandbox Code Playgroud)
这很奇怪,因为第二个baz方法不适用于此上下文,因为参数数量不匹配.我看了JLS8(15.13).但是,它没有帮助,因为方法引用的规则非常复杂.
问:为什么第二种情况会出现编译错误?根据JLS真的会出现编译错误吗?根据对另一个问题的一些评论,Netbeans中没有编译错误.
作为参考,我使用的是JDK8版本1.8.0-b132.如果在命令行上编译程序,编译器将显示以下错误消息:
$ /opt/jdk8/bin/javac Foo.java
Foo.java:6: …
Run Code Online (Sandbox Code Playgroud) 我最近了解到,自几年以来,libstdc ++库包含vstring
(也称为versa_string
),它提供了相同的功能std::string
,但显然更符合C++标准.我曾试图用它vstring
作为替代品std::string
,但我发现没有简单的方法可以做到.
有没有一种简单的方法来代替std::string
用vstring
,在不改变的libstdc ++源代码?
我可以用std::string
别名替换代码中的所有用法,如下面的清单所示.然而,这种方法的问题在于,它std::string
也在某些地方内部使用,例如在std::ostringstream
.这意味着,这些陈述std::ostringstream os; my::string s = os.str();
不再适用.
namespace my {
#ifdef __GLIBCXX__
using string = __gnu_cxx::__vstring;
#else
using string = std::string;
#endif
}
Run Code Online (Sandbox Code Playgroud) 最近我注意到这个函数std::string::find
比函数慢了一个数量级std::strstr
- 在我的环境中使用Linux上的GCC 4.7.性能差异取决于字符串的长度和硬件架构.
差异似乎有一个简单的原因:std::string::find
基本上是std::memcmp
在一个循环中调用- 具有时间复杂性O(m * n)
.相比之下,std::strstr
它针对硬件架构进行了高度优化(例如,使用SSE指令),并使用更复杂的字符串匹配算法(显然是Knuth-Morris-Pratt).
我也很惊讶没有在语言文件中找到这两个功能的时间复杂性(即草稿N3290和N1570).我只发现了时间的复杂性char_traits
.但这没有用,因为没有子字符串搜索功能char_traits
.
我希望,这std::strstr
和memmem
含有类似优化几乎相同的性能.直到最近,我认为内部std::string::find
使用memmem
.
问题是:有什么好的理由,为什么std::string::find
不使用std::memmem
?它在其他实现中有所不同吗?
问题不是:这个功能的最佳实现是什么?如果它比C慢,那么对C++来说真的很难说.如果两个实现都很慢,我就无所谓了.真正伤害的是性能差异.