据我所知,写时复制不是std::string在C++ 11中实现符合性的可行方法,但最近在讨论中我发现自己无法直接支持该语句.
我是否正确C++ 11不承认基于COW的实现std::string?
如果是这样,这个限制是否在新标准(其中)的某处明确说明了?
或者这个限制是否暗示,因为新要求的综合影响std::string排除了基于COW的实施std::string.在这种情况下,我会对"C++ 11有效禁止基于COW的std::string实现" 的章节和样式推导感兴趣.
这最近出现在代码审查讨论中,但没有令人满意的结论.有问题的类型是C++ string_view TS的类似物.它们是指针和长度周围的简单非拥有包装器,装饰有一些自定义函数:
#include <cstddef>
class foo_view {
public:
foo_view(const char* data, std::size_t len)
: _data(data)
, _len(len) {
}
// member functions related to viewing the 'foo' pointed to by '_data'.
private:
const char* _data;
std::size_t _len;
};
Run Code Online (Sandbox Code Playgroud)
出现的问题是,是否有一种方法可以通过值或const引用来传递这些视图类型(包括即将发生的string_view和array_view类型).
支持传递值的参数等于"减少输入","如果视图具有有意义的突变,则可以改变本地副本",并且"可能效率不低".
支持pass-by-const-reference的参数相当于"通过const&'传递对象更加惯用,而'可能效率不低'.
是否有任何额外的考虑因素可以通过一种或另一种方式最终通过值或const引用传递惯用视图类型.
对于这个问题,可以安全地假设C++ 11或C++ 14语义,以及足够现代的工具链和目标体系结构等.
我有一个模板'Foo',它拥有一个T,我希望它有一个可变参数构造函数,将它的参数转发给T的构造函数:
template<typename T>
struct Foo {
Foo()
: t() {}
Foo(const Foo& other)
: t(other.t) {}
template<typename ...Args>
Foo(Args&&... args)
: t(std::forward<Args>(args)...) {}
T t;
};
Run Code Online (Sandbox Code Playgroud)
但是,这会导致Foo无法复制:
int main(int argc, char* argv[]) {
Foo<std::shared_ptr<int>> x(new int(42));
decltype(x) copy_of_x(x); // FAILS TO COMPILE
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
因为,根据这个答案,参数的非常量导致可变参数构造函数更好地匹配.出于显而易见的原因,我不想强制我的调用者使用const_cast.
我找到的一个可能的解决方案是为Foo编写一个"复制构造函数",它采用非const Foo并使用构造函数转发:
Foo(Foo& other)
: Foo(const_cast<const Foo&>(other)) {}
Run Code Online (Sandbox Code Playgroud)
当定义了这个构造函数时,事情再次起作用:现在首选非const Foo参数copy ctor.然而,这对我来说似乎非常粗略,因为这种"治愈"似乎比疾病更糟糕.
是否有另一种方法来实现这种效果,表明自然拷贝构造函数应该优先于可变参数构造函数?如果没有,定义这个非const参数复制构造函数会有什么不利后果吗?
下面是一个简单的程序,它在共享库中使用非POD类型的C++ 11 thread_local变量进行测试.
如果我使用自制软件,这很好用:
> /usr/local/Cellar/llvm/3.5.0_2/bin/clang --version
clang version 3.5.0 (tags/RELEASE_350/final)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
> cmake .. -G Ninja -DCMAKE_C_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/Cellar/llvm/3.5.0_2/bin/clang++
-- The C compiler identification is Clang 3.5.0
-- The CXX compiler identification is Clang 3.5.0
-- Check for working C compiler using: Ninja
-- Check for working C compiler using: Ninja -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler using: Ninja
-- …Run Code Online (Sandbox Code Playgroud) 在Ubuntu 14.10上,llvm-symbolizer程序安装为/usr/bin/llvm-symbolizer-3.5.通常情况下,地址消毒剂希望找到一个名为二进制llvm-symbolizer在PATH.但是,作为一种解决方法,可以明确设置ASAN_SYMBOLIZER_PATH.因此,ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5在环境中设置会让地址清理程序检测程序打印符号化错误.
在Ubuntu 16.04上,llvm-symbolizer程序再次安装了版本后缀,现在为/usr/bin/llvm-symbolizer-3.8.但是,ASAN_SYMBOLIZER_PATH设置似乎不再起作用.ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.8当ASAN检测到错误时,在环境中运行带有set 的ASAN检测程序会生成以下错误:
==18718==ERROR: External symbolizer path is set to '/usr/bin/llvm-symbolizer-3.8' which isn't a known symbolizer. Please set the path to the llvm-symbolizer binary or other known tool.
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么这种行为改变了,或者如何恢复旧的行为?这似乎是不合理的限制.我指向ASAN的符号化程序绝对是一个已知的符号化器,它恰好在最后有一个Ubuntu强制版本标签.
请注意,调整PATH在这里没有用,因为Ubuntu不提供没有llvm-symbolizer版本装饰的二进制文件.
我很惊讶地发现is_swappable<T>并且is_nothrow_swappable<T>不属于新的C++ 11 type_traits元函数.它们对于传播noexcept模板和确定是否可以为模板实现非抛出交换非常有用.
的libc ++推出其自己的内部版本:看__is_swappable和__is_nothrow_swappable在其版本type_traits的,它使大量的内部使用它们,但不会让他们提供给外部.
我最终将我自己的这些版本拼凑起来用于个人项目,这似乎有效,但我确定它会以某种方式破坏.
我很好奇这两个缺席,因为它们看起来非常重要.在C++ 11标准化过程中是否考虑过此功能,还是仅仅是一个未包含在内的疏忽?如果考虑到了什么,导致它没有被纳入最终标准(缺乏时间,实施问题等)?是否有缺陷报告或进化论文讨论这个问题?有没有计划在C++ 1Y中加入这些特性?某处有一个公认的"正确"版本吗?
在ELF目标上,如果我已经通过类似的声明class Foo给予它default可见性class __attribute__((visibiility("default"))) Foo,那么我可以选择性地default通过明确地用它们注释来使类的某些成员免于可见性__attribute__((visibility("hidden")).这对于不应构成ABI一部分的内联方法非常有用,因此如果在构建库定义时发出class Foo它们,则不会导出它们,或者其中的private成员或类型class Foo也不应构成其ABI的一部分.
但是,在Windows上,似乎没有办法实现这一目标.虽然unadorned class Foo自动私有DLL,但一旦被装饰为class __declspec(dllexport) Foo,整个类现在都是dllexport,并且似乎没有可以选择性地覆盖__dllexport特定成员状态的关联注释.标记选择"不用于导出"成员__declspec(dllimport)显然是错误的.
是否有其他方法可以阻止类作用域__dllexport应用于某些类成员和/或类型?
为了使这更具体,我想说的,并且可以说,当使用ELF注释时:
class __attribute__((visibility("default"))) Foo {
public:
Foo(); // OK, default visibility
// Don't let inlines join the ABI
__attribute__((visibility("hidden")) inline void something() { ... }
private:
// Don't let private members join the ABI
__attribute__((visibility("hidden")) void _internal();
// Our pImpl type …Run Code Online (Sandbox Code Playgroud) 我(大部分)成功为googletest设置了ExternalProject_Add.但是,我注意到我选择的C++编译器,构建类型等不会自动转发到ExternalProject.
我可以通过在调用ExternalProject_Add时将它添加到CMAKE_ARGS来轻松添加任何给定的标志,如下所示:
CMAKE_ARGS -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS}
Run Code Online (Sandbox Code Playgroud)
但是,这要求我枚举应转发给googletests的CMake调用的所有可能参数,并且该列表非常庞大.我还需要为我想要的每个其他ExternalProject_Add创建相同的列表.这似乎很脆弱,容易出错.
有没有办法告诉CMake"转发"用户提供的配置?换句话说,如果我调用CMake为:
cmake <path-to-project> -DCMAKE_C_COMPILER=/usr/bin/clang -DSOME_RANDOM_FLAG=stuff
Run Code Online (Sandbox Code Playgroud)
然后我希望我对ExternalProject_Add的调用提供相同的编译器选择和值SOME_RANDOM_FLAG,而无需显式列出这些名称.我不确定只是简单地传递CMake的ARGV会起作用,因为说
CC=/usr/bin/clang cmake <path-to-project>
Run Code Online (Sandbox Code Playgroud)
理想情况下也会有效.
有关如何实现这一点的任何想法?
在OS X 10.8上使用libc ++时,以下代码无法使用XCode 4.5的clang ++进行编译:
#include <map>
#include <string>
class Foo {
public:
explicit Foo(int val_) : val(val_) {}
int val;
};
struct FooComparator {
bool operator()(const Foo& left, const Foo& right) {
return left.val < right.val;
}
};
int main(int argc, char* argv[]) {
std::map<Foo, std::string, FooComparator> m;
Foo f(4);
m[f] = std::string("four");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误:
broken.cpp:11:8:注意:候选函数不可行:'this'参数的类型为'const FooComparator',但是方法没有标记为const bool operator()(const Foo&left,const Foo&right){
如果我关闭libc ++并使用libstdc ++构建,那么一切都很好.显然,我可以通过制作FooComparator :: operator()const来解决这个问题,但是我想知道这是否是libc ++过于严格的问题,还是标准(C++ 03和C++ 11)确实要求比较器的operator()是const(在这种情况下,它与libstdc ++一起工作的事实是一个幸福的事故).
请考虑以下内容,其中我们在不同的转换单元中有两个文件范围的对象,这是通过初始化顺序fiasco的未定义行为的常规设置:
a.hpp:
struct thing {
public:
thing(int value);
~thing();
int value() const;
static int count();
private:
int _value;
};
Run Code Online (Sandbox Code Playgroud)
a.cpp:
#include "a.hpp"
#include <atomic>
namespace {
std::atomic<int> things;
}
thing::thing(int value) : _value(value) {
++things;
}
thing::~thing() {
--things;
}
int thing::value() const {
return _value;
}
int thing::count() {
return things.load();
}
Run Code Online (Sandbox Code Playgroud)
b.cpp:
#include <iostream>
#include "a.hpp"
namespace {
thing static_thing(42);
}
void foo() {
std::cout << static_thing.value() << ' ' << thing::count() << '\n';
} …Run Code Online (Sandbox Code Playgroud)