小编Eri*_*c Z的帖子

在涉及数组时,不应该声明与其定义匹配吗?

我的程序中有两个源文件.

数组在A.cpp中定义.

// compiler: MSVC2005 SP2    
// A.cpp

// defines an array of type "int [100]"
int a[100] = {3};
Run Code Online (Sandbox Code Playgroud)

它用于B.cpp.

// B.cpp

// declares an array of type "int []"
extern int a[];

int main()
{
  // prints 3 correctly
  cout << a[0] << endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

AFAIK,如果使用声明的标识符,如果找不到声明的任何匹配定义,则链接器将引发错误.这里,int []int [100]显然是两种不同的类型.

在这种情况下,为什么没有链接错误?标准是否保证在声明/定义匹配期间数组大小是微不足道的?或者它只是特定于实现?如果有的话,将赞赏标准的引用.

编辑: iammilind在他的回答中提到链接器可以正确运行(他的编译器是gcc),即使声明和定义之间的类型不匹配.是标准要求还是gcc的方式?我想这是一个非常重要的问题.

c++ arrays

8
推荐指数
1
解决办法
218
查看次数

带有两个变量的Big-O表示法

这源于编写程序以找到具有大小mn分别具有时间复杂度的两个排序数组的中值O(log(m + n)).

我可以找出解决方案O(log(m) + log(n)).它符合上述时间要求吗?

我认为这是积极的,因为:

log(m) + log(n) = log(m*n) <= log((m+n)^2) = 2*log(m+n) = O(log(m+n))

换句话说,存在k = 2m0 = n0 = 1.对于任何m > m0 and n > n0,有log(m*n) <= k*log(m + n).

是否存在缺陷,或者我是否正确?

更一般地说,给定常数a,我们可以log(n^a) = O(log(n))用相同的推理说出来吗?


感谢大卫的回答.维基百科上的Big-O表示法也提到了这一点:

"We may ignore any powers of n inside of the logarithms. The set O(log n) …

algorithm big-o

8
推荐指数
1
解决办法
1851
查看次数

断言失败的策略是什么?

断言用于检查是否满足条件(前置条件,后置条件,不变量),并帮助程序员在调试阶段找到漏洞.

例如,

void f(int *p)
{
  assert(p);
  p->do();
}
Run Code Online (Sandbox Code Playgroud)

我的问题是我们是否需要假设在发布模式下无法满足条件并相应处理案例?

void f(int *p)
{
  assert(p);

  if (p)
  {
    p->do();
  }
}
Run Code Online (Sandbox Code Playgroud)

毕竟,断言意味着它所测试的条件永远不应该是假的.但是,如果我们不检查它并且它失败了,程序崩溃了.听起来像是两难.你们怎么处理它?

c++ assertion

7
推荐指数
1
解决办法
5868
查看次数

在不使用堆栈的情况下从中缀表达式构建二叉树

最近我写了一个算法convert an infix expression to a binary tree without using any stack.但是,当我在网上搜索时,我发现那里描述的算法都基于堆栈(或递归).

所以我开始担心我的算法的正确性,虽然我不能证明它是不正确的.

你知道技术上是否可以在没有任何堆栈的情况下转换它?我的算法错了吗?

简短的介绍

它基于:

  1. 中缀表达式中的操作数属于其前面的运算符的右子节点,或者属于它后面的运算符的左子节点.

  2. 如果运算符的OP2优先级高于其前一个运算符OP1,则前一个操作数x将成为其子类OP2,并OP2成为其子类OP1.

  3. 如果运算符的OP2优先级低于其前一个运算符OP1,则前一个操作数x将成为正确的子级OP1.从树上移OP1,比较每个祖先的优先级OP1OP2直到OP2<=祖先的优先级OP.然后OP2成为正确的孩子OP.

该程序

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

using namespace std;

typedef struct Node{
   // store operator or operand
   string data;
   // only …
Run Code Online (Sandbox Code Playgroud)

c++ algorithm

7
推荐指数
1
解决办法
9723
查看次数

在C++ 11中排序之前的关系会阻止编译器/ CPU重新排序吗?

我知道,现代C++编译器和处理器通常会通过重新排序指令来执行某些优化,以获得更好的性能.

C++ 11 关系之前引入了一个顺序.如果指令在程序顺序的指令A之前到来B,我们说之前A顺序的 B.

int data = 0;
bool ready = 0;

// A is sequenced before B
data = 6;      // A
ready = true;  // B
Run Code Online (Sandbox Code Playgroud)

C++ 11还定义了关系之前排序的要求.

给定任何两个评估A和B,如果A在B之前被排序,那么A的执行应该在B的执行之前.

这让我很困惑.对我而言,它与无序执行相冲突,因为重新排序可能会破坏上述所需的属性.例如,当商店ready发生在商店之前data.

上面的定义是否会停止指令重新排序?(我很确定不是.但是我错过了什么?)

c++ language-lawyer c++11

7
推荐指数
1
解决办法
342
查看次数

atomic_thread_fence(memory_order_seq_cst)是否具有完整内存屏障的语义?

完整/通用内存屏障是在屏障之前指定的所有LOAD和STORE操作看起来发生在屏障之后相对于系统的其他组件指定的所有LOAD和STORE操作之前的屏障.

根据cppreference,memory_order_seq_cst等于memory_order_acq_rel在所有标记的操作上加上单个总修改顺序.但据我所知,C++ 11中的获取和释放栏都没有强制执行#StoreLoad(加载后存储)排序.发布围栏要求以后的任何写入都不能重新排序先前的读/写; 获取围栏要求不能对任何先前的读取重新排序后续读/写.如果我错了,请纠正我;)

举个例子,

atomic<int> x;
atomic<int> y;

y.store(1, memory_order_relaxed);            //(1)
atomic_thread_fence(memory_order_seq_cst);   //(2)
x.load(memory_order_relaxed);                //(3)
Run Code Online (Sandbox Code Playgroud)

是否允许优化编译器将指令(3)重新排序到之前(1),以使其有效看起来像:

x.load(memory_order_relaxed);                //(3)
y.store(1, memory_order_relaxed);            //(1)
atomic_thread_fence(memory_order_seq_cst);   //(2)
Run Code Online (Sandbox Code Playgroud)

如果这是一个有效的转换,那么它证明atomic_thread_fence(memory_order_seq_cst)并不一定包含完整障碍所具有的语义.

c++ c++11

7
推荐指数
2
解决办法
1256
查看次数

可以通过这种方式实现"struct hack"吗?

Struck hack用于分配比结构本身初始需要更多的内存,以便您可以引用数组的越界部分,以便保留在实际分配的内存中.

这是它的工作原理.

struct Foo
{
  // ..
  size_t size;
  int data[1];
};

const size_t SIZE = 100;
Foo *p = (Foo*) malloc(sizeof(Foo) + sizeof(int) * (SIZE - 1));
p->size = SIZE;
for (int i = 0; i < p->size; ++i) (p->data)[i] = i;
Run Code Online (Sandbox Code Playgroud)

题:

我们可以只使用一个整数而不是一个大小为1的数组吗?如果这是可行的,那么为什么数组大小版本变得更受欢迎呢?

struct Foo
{
  // ..
  size_t size;
  int data;
};

// ..
for (int i = 0; i < p->size; ++i) (&p->data)[i] = i;
Run Code Online (Sandbox Code Playgroud)

c++ struct

6
推荐指数
3
解决办法
624
查看次数

为什么跳转到没有初始化器的标量类型对象的范围?

当我正在阅读C++标准时,根据标准,以下代码似乎完全正常.

int main() {
   goto lol;
   {
      int x;
lol:
      cout << x << endl;
   }
}

// OK
Run Code Online (Sandbox Code Playgroud)

[n3290:6.7/3]:可以转换为块,但不能以初始化绕过声明的方式.从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的,除非该变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始化程序的情况下声明.

它为什么要起作用?跳过它的定义并使用undefined不是很危险x吗?为什么初始化器的存在会有什么不同?

c++ goto

6
推荐指数
1
解决办法
121
查看次数

返回的字符串是否从getline()以null结尾?

谷歌搜索一段时间之后我不太确定的一件事是返回的getline()字符串.希望在这里得到确认.

std::getline
Run Code Online (Sandbox Code Playgroud)

这个全局版本返回一个std :: string,因此它不一定是以null结尾的.有些编译器可能附加'\ 0'而其他编译器则不会.

std::istream::getline
Run Code Online (Sandbox Code Playgroud)

此函数返回一个c样式的字符串,因此可以保证字符串以空值终止.

是对的吗?

c++ string getline

6
推荐指数
1
解决办法
3406
查看次数

正确使用shared_ptr来消除DLL边界的重新分配

我正在阅读" 在dll-interfaces中使用shared_ptr ".在那篇文章中,phlipsy提出了一种方法,在他的答案结束时,不跨DLL边界传递任何特定于实现的对象.基本上,我们的想法是从DLL返回一个原始指针,并shared_ptr在原始指针的EXE中初始化.

我不认为这是正确的.让我为了简单而重新定型.

// wrong version??
// DLL
Object* createObject()
{
  return new Object;
}

// EXE
std::tr1::shared_ptr<Object> p(createObject());
..
Run Code Online (Sandbox Code Playgroud)

object被释放,由所使用的破坏上下文/堆shared_ptr是从施工过程中DLL使用的不同.

正确的使用方法shared_ptr是资源分配应该与初始化相同shared_ptr,因此分配和释放可以使用相同的堆,如下所示.

// right version
// DLL
std::tr1::shared_ptr<Object> createObject()
{
  return std::tr1::shared_ptr<Object>(new Object);
}

// EXE
std::tr1::shared_ptr<Object> p(createObject());
..
Run Code Online (Sandbox Code Playgroud)

我对吗?

c++ shared-ptr

5
推荐指数
1
解决办法
3414
查看次数