所以这里有一个小测试程序:
#include <string>
#include <iostream>
#include <memory>
#include <vector>
class Test
{
public:
Test(const std::vector<int>& a_, const std::string& b_)
: a(std::move(a_)),
b(std::move(b_)),
vBufAddr(reinterpret_cast<long long>(a.data())),
sBufAddr(reinterpret_cast<long long>(b.data()))
{}
Test(Test&& mv)
: a(std::move(mv.a)),
b(std::move(mv.b)),
vBufAddr(reinterpret_cast<long long>(a.data())),
sBufAddr(reinterpret_cast<long long>(b.data()))
{}
bool operator==(const Test& cmp)
{
if (vBufAddr != cmp.vBufAddr) {
std::cout << "Vector buffers differ: " << std::endl
<< "Ours: " << std::hex << vBufAddr << std::endl
<< "Theirs: " << cmp.vBufAddr << std::endl;
return false;
}
if (sBufAddr != cmp.sBufAddr) {
std::cout …
Run Code Online (Sandbox Code Playgroud) 在这样的代码中:
#include <iostream>
#include <initializer_list>
#include <string>
struct A
{
A() { std::cout << "2" << std::endl; }
A(int a) { std::cout << "0" << std::endl; }
A(std::initializer_list<std::string> s) { std::cout << "3" << std::endl; }
A(std::initializer_list<int> l) { std::cout << "1" << std::endl; }
};
int main()
{
A a1{{}};
}
Run Code Online (Sandbox Code Playgroud)
为什么调用std::initializer_list<int>
构造函数的规范?如果我们定义构造函数,它会产生歧义编译错误std::initializer_list<double>
.这种结构的规则是什么?为什么std::initializer_list
数字作为模板参数如此具体?
这里我有一些简单的代码:
#include <iostream>
#include <cstdint>
int main()
{
const unsigned char utf8_string[] = u8"\xA0";
std::cout << std::hex << "Size: " << sizeof(utf8_string) << std::endl;
for (int i=0; i < sizeof(utf8_string); i++) {
std::cout << std::hex << (uint16_t)utf8_string[i] << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里看到 MSVC 和 GCC 的不同行为。MSVC 认为"\xA0"
未编码的 unicode 序列,并将其编码为 utf-8。所以在 MSVC 中,输出是:
C2A0
这是在 utf8 unicode 符号中正确编码的U+00A0
。
但是在 GCC 的情况下,什么也没有发生。它将字符串视为简单的字节。即使我u8
在字符串文字之前删除也没有变化。
这两种编译器编码与输出UTF8C2A0
如果字符串设定为:u8"\u00A0";
为什么编译器的行为不同,哪个实际上是正确的?
用于测试的软件:
海湾合作委员会 8.3.0
MSVC 19.00.23506
C++ 11
假设我有界面:
class MyInterface
{
public:
virtual ~MyInterface() = default;
virtual void DoSomething(const MyType& a, const MyTypeB& b);
};
Run Code Online (Sandbox Code Playgroud)
我想要的是如果任何函数参数是右值或左值引用,则允许使用移动语义。
我不想要的是像这样定义接口:
class MyInterface
{
public:
virtual ~MyInterface() = default;
virtual void DoSomething(const MyType& a, const MyTypeB& b);
virtual void DoSomething(MyType&& a, const MyTypeB& b);
virtual void DoSomething(const MyType& a, MyTypeB&& b);
virtual void DoSomething(MyType&& a, MyTypeB&& b);
};
Run Code Online (Sandbox Code Playgroud)
如果向方法中添加更多参数,组合数学会变得更糟。
因此,在实现中,如果我传递了右值,我基本上想移动参数,否则进行复制。
标准库中有std::forward
,但它与所谓的“转发引用”一起使用,这需要模板,并且在虚拟方法中不可能有模板参数。
有没有什么方法可以做到这一点,同时保留接口基类型的目的,并且不会使接口本身变得如此膨胀?
我已经研究了一些库的代码,并注意到那里的调用calloc
后面跟着memset
分配的块calloc
.我发现这个问题有一个非常全面的答案,关于calloc
和malloc
+ 之间的差异,并在分配存储之前memset
调用memset
:
我仍然无法理解的是为什么人们会这样做.这项业务有什么好处?
上面提到的代码示例库:
light_pcapng_file_info *light_create_default_file_info()
{
light_pcapng_file_info *default_file_info = calloc(1, sizeof(light_pcapng_file_info));
memset(default_file_info, 0, sizeof(light_pcapng_file_info));
default_file_info->major_version = 1;
return default_file_info;
}
Run Code Online (Sandbox Code Playgroud)
分配结构的代码(每个数组包含32个元素):
typedef struct _light_pcapng_file_info {
uint16_t major_version;
uint16_t minor_version;
char *file_comment;
size_t file_comment_size;
char *hardware_desc;
size_t hardware_desc_size;
char *os_desc;
size_t os_desc_size;
char *user_app_desc;
size_t user_app_desc_size;
size_t interface_block_count;
uint16_t link_types[MAX_SUPPORTED_INTERFACE_BLOCKS];
double timestamp_resolution[MAX_SUPPORTED_INTERFACE_BLOCKS];
} light_pcapng_file_info;
Run Code Online (Sandbox Code Playgroud)
编辑:
除了接受的答案,我想提供一些我的同事指出的信息.glibc中有一个错误,有时会阻止calloc将内存清零.这是链接:https: //bugzilla.redhat.com/show_bug.cgi?id = 1293976
案例链接移动时的实际错误报告文本:
glibc:calloc()返回非零内存 …
我这里有代码:
#include <string>
#include <iostream>
#include <initializer_list>
template <typename T>
class Test
{
public:
Test(std::initializer_list<T> l)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test(const Test<T>& copy)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test(Test&&) = delete;
Test() = delete;
};
void f(const Test<Test<std::string>>& x)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void f(const Test<std::string>& x)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
f(Test<Test<std::string>>{x});
}
int main()
{
Test<std::string> t1 {"lol"};
f(t1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我尝试用我的linux mint 19上的GCC 7.3.0编译这个命令:
g ++ -std …
我在 C 中有 2 个函数:
void func1(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
}
void func2(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
unsigned char b[10];
b[0] = 4;
b[9] = 5;
}
Run Code Online (Sandbox Code Playgroud)
编译:
gcc 7.3 x86-64
-O0 -g
操作系统:
16.04.1-Ubuntu x86-64
生产的英特尔功能组装:
func1(unsigned char):
pushq %rbp
movq %rsp, %rbp
movl %edi, %eax
movb %al, -68(%rbp)
movb $1, -64(%rbp)
movb $2, -15(%rbp)
nop
popq %rbp
ret
func2(unsigned char):
pushq …
Run Code Online (Sandbox Code Playgroud) 使用默认删除器是否安全std::unique_ptr
?
我想这样使用它:
uint8_t* binaryData = new uint8_t[binaryDataSize];
std::unique_ptr<uint8_t> binPtr(binaryData);
Run Code Online (Sandbox Code Playgroud)
所以默认的删除器std::unique_ptr
看起来像这样:
template<typename _Up>
typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
operator()(_Up* __ptr) const
{
static_assert(sizeof(_Tp)>0,
"can't delete pointer to incomplete type");
delete [] __ptr;
}
Run Code Online (Sandbox Code Playgroud)
从我的观点来看,使用由原始指针分配的原始指针是new[]
安全的,而不是由分配的原始指针安全std::malloc
.我错过了什么吗?有更好的解决方案吗?