标签: c++

为什么在std :: move之后需要调用析构函数?

在C++编程语言第4版中,有一个向量实现的示例,请参阅消息末尾的相关代码.

uninitialized_move()通过从旧内存区域移动新T对象将其初始化到新内存区域.然后它调用原始T对象上的析构函数,即移动对象.为什么在这种情况下需要析构函数调用?

这是我的不完全理解:移动对象意味着移动对象拥有的资源的所有权被转移到移动对象.移动对象中的剩余部分是一些不需要销毁的内置类型的可能成员,当vector_base b超出范围时(在reserve ()调用之后,它们将被释放)).移动对象中的所有指针都将被置于nullptr或者使用某种机制来删除这些资源上移动对象的所有权以便我们安全,那么为什么在"vector_base b"时调用耗尽对象上的析构函数"在交换完成后,析构函数仍会解除内存的释放?

我理解在必须调用析构函数时需要显式调用析构函数,因为我们有一些东西需要破坏(例如drop元素)但是在vector_base的std :: move + deallocation之后我看不到它的含义.我在网上阅读了一些文本,我看到被移动对象的析构函数调用作为对象生命周期结束的信号(对谁或什么?).

请告诉我,析构函数还有哪些有意义的工作要做?谢谢!

下面的代码片段来自http://www.stroustrup.com/4th_printing3.html

template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=capacity()) return;                   // never decrease allocation
    vector_base<T,A> b {vb.alloc,size(),newalloc-size()};   // get new space
    uninitialized_move(vb.elem,vb.elem+size(),b.elem);  // move elements
    swap(vb,b);                                 // install new base 
} // implicitly release old space

template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
    using T = Value_type<Out>;      // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_) …
Run Code Online (Sandbox Code Playgroud)

c++ memory-management move-semantics c++11 explicit-destructor-call

24
推荐指数
1
解决办法
1万
查看次数

C和C++中float和double的大小是多少?

我正在寻找是否有任何类似的标准类型uint32_t总是映射到32位无符号整数类型,但我找不到任何.

float所有平台上的大小总是4字节?
大小double总是8?

两种标准都有关于此事的任何说法吗?

我想确保我的大小在所有平台(x86和x64)上总是相同的,所以我使用标准的int类型,但我找不到任何类似的typedef for floatdouble.

c c++ floating-point 64-bit x86

24
推荐指数
4
解决办法
7万
查看次数

为什么指向int的指针转换为void*但指向函数的指针转换为bool?

C++草案标准(N3337)有关于指针转换的以下内容:

4.10指针转换

2类型的右值"指针CV T ",其中T是对象类型,可被转化为式的一个右值"指针CV void ".一个"指针转换的结果CV T "发送给"指针CV void "指向类型对象T所在的存储位置的起始位置,就好像该对象是类型最派生的对象(1.8)T(即不是基类子对象).

4.12布尔转换

1算术,枚举,指针或指向成员类型的指针的右值可以转换为类型的右值bool.零值,空指针值或空成员指针值转换为false; 任何其他值都转换为true

基于以上所述,将函数指针或指针转换int为a void*也是完全可以的bool.

但是,考虑到两者的选择,指针应该转换为哪一个?

然后,为什么指向函数的指针转换为a bool和指向int转换为void*?的指针?

程序:

#include <iostream>
using namespace std;

void foo(const void* ptr)
{
   std::cout << "In foo(void*)" << std::endl;
}

void foo(bool b)
{
   std::cout << "In foo(bool)" << std::endl;
}

void bar()
{
}

int main()
{
   int i …
Run Code Online (Sandbox Code Playgroud)

c++ pointers c++11

24
推荐指数
1
解决办法
1806
查看次数

从左到右的结合意味着什么?

我对从左到右和从右到左的相关性的定义感到困惑.我也看到他们被称为左关联和右关联,并想知道哪个对应哪个.

我知道它与执行具有相同优先级的操作的顺序有关,如a = x*y*z是指a = x*(y*z)还是a =(x*y)*z.我不知道哪一个是从左到右的关联,哪个是从右到左的关联.

我已经尝试了谷歌它,但我能找到的是不同运算符在c ++中的相关性的表格.看看所有的例子让我更加困惑.

让我更进一步困惑的是:

glm::vec4 transformedVector = translationMatrix * rotationMatrix * scaleMatrix * originalVector;
Run Code Online (Sandbox Code Playgroud)

首先预先形成缩放矩阵乘法,然后是旋转矩阵,然后是平移.在这个例子中,矩阵都是glm :: mat4类型,向量是glm :: vec4类型.这是从左到右还是从右到左的关联性?这与正常乘法相同还是glm类型的乘法不同?

c++ glm-math

24
推荐指数
3
解决办法
2万
查看次数

dynamic_cast <void*>什么时候有用?

5.2.7/7说的内容如下:

如果T是"指向cv void",则结果是指向由其指向的派生类最多的指针x.

这个synatx有什么好的应用?什么时候应该dynamic_cast<void*>使用?

c++ dynamic-cast casting void-pointers c++11

24
推荐指数
2
解决办法
2195
查看次数

stl中的一些容器没有查找功能

一些STL容器例如std::liststd::vector没有find()方法作为成员函数.这是为什么?我知道有使用的替代std::find<algorithm>,但仍然使用这也不是100%纯天然.

c++ containers stl

24
推荐指数
3
解决办法
1899
查看次数

Clang vs GCC vs MSVC模板转换运算符 - 哪个编译器是对的?

我有简单的代码与转换运算符,似乎所有编译器给出不同的结果,好奇哪个编译器,如果有的话,是正确的?我尝试了不同的组合,但下面的组合是最有趣的.代码是使用C++ 11标志编译的,但在C++ 03中也可能会出现相同的行为.

#include <iostream>

struct call_operator {
    template<typename T>
    operator T() {
        std::cout << __FUNCTION__ << std::endl;
        return {};
    }

    template<typename T>
    operator const T&() const {
        std::cout << __FUNCTION__ << std::endl;
        static T t;
        return t;
    }

    template<typename T>
    operator T&() const {
        std::cout << __FUNCTION__ << std::endl;
        static T t;
        return t;
    }
};

int main() {
    (void)static_cast<int>(call_operator());
    (void)static_cast<const int&>(call_operator());
    (void)static_cast<int&>(call_operator());
}
Run Code Online (Sandbox Code Playgroud)

铛 - 3.6:

operator int
operator const int &
operator int &
Run Code Online (Sandbox Code Playgroud)

克++ - 4.9: …

c++ gcc clang visual-c++ c++11

24
推荐指数
1
解决办法
1429
查看次数

代码对象和可执行文件之间的区别

我是一名C++初学者,我正在研究该语言的基础知识.我的书中有一个关于编译器的主题,我的问题是我无法理解文本想要说的内容:

C++是一种编译语言,因此您需要将源代码转换为计算机可以执行的文件.该文件由编译器生成,称为目标代码(.obj),但像"hello world"程序这样的程序由我们编写的部分和C++库的一部分组成.链接器链接程序的这两部分并生成可执行文件(.exe).

为什么我的书告诉计算机执行的文件是带有obj后缀的文件(目标代码),然后说它是带有exe后缀的文件?

c++ linker

24
推荐指数
3
解决办法
3万
查看次数

保证静态对象的静态(常量)初始化

首要问题是:程序员如何确保通过静态初始化而不是通过动态初始化来初始化他的非本地静态变量?

由于始终进行零初始化,因此应该查看常量初始化.

3.6.2.2对象的常量初始化器o是一个表达式,它是一个常量表达式,除了它也可以为o及其子对象调用constexpr构造函数,即使这些对象是非文字类类型[注意:这样的类可能有一个非平凡的析构函数 - 注意事项].执行常量初始化:

- 如果在具有静态或线程存储持续时间的引用的初始值设定项中出现的每个完整表达式(包括隐式转换)是常量表达式(5.19)并且引用绑定到指定具有静态存储持续时间的对象的左值或者临时的(见12.2);

- 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,并且初始化full-expression是对象的常量初始化器 ;

- 如果具有静态或线程存储持续时间的对象未通过构造函数调用初始化,并且该对象是值初始化的,或者其初始化程序中出现的每个完整表达式都是常量表达式.

我省略了引用,因为它在我的情况下并不重要.如何理解标准是有3种情况:

  1. 构造函数
  2. no-ctor和值初始化
  3. 没有和不断表达

假设我有以下课程:

struct X {
  bool flag = false;
  // = {} will break VS2013 CTP so in that case use the
  // regular ctor, which sadly still can't be declared constexpr
  std::aligned_storage<sizeof(int), alignof(int)>::type storage = {};
};
Run Code Online (Sandbox Code Playgroud)

据我所知,这个类对于常量初始化是完全有效的(每个元素都可以不断初始化).这是真的?

这个类需要constexpr构造函数吗?

C++ 11和C++ 98是否保证了常量初始化?

附带问题:如果是/ dll,静态初始化什么时候完成?在加载时间内,还是可能会进一步延迟?

c++ c++11

24
推荐指数
1
解决办法
1000
查看次数

C++:Stack的push()vs emplace()

试图理解使用push()emplace()for 之间的区别std::stack.

我在想,如果我创建一个std::stack<int>,那么我会使用push()因为整数是一种原始类型而且没有任何东西emplace()需要构造.

但是,如果我正在创建,std::stack<string>那么我会选择emplace()因为std::string是一个对象.

这是正确的用法吗?

c++ stack

24
推荐指数
2
解决办法
2万
查看次数